public ThreadWorker (IScheduler sched, ThreadWorker[] others, IProducerConsumerCollection<Task> sharedWorkQueue, bool createThread, int maxStackSize, ThreadPriority priority) { this.others = others; // if (!string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("USE_CYCLIC"))) { // Console.WriteLine ("Using cyclic deque"); // this.dDeque = new CyclicDeque<Task> (); // } else { // this.dDeque = new DynamicDeque<Task> (); // } this.dDeque = new CyclicDeque<Task> (); this.sharedWorkQueue = sharedWorkQueue; this.workerLength = others.Length; this.isLocal = !createThread; this.childWorkAdder = delegate (Task t) { dDeque.PushBottom (t); sched.PulseAll (); }; // Find the stealing start index randomly (then the traversal // will be done in Round-Robin fashion) do { this.stealingStart = r.Next(0, workerLength); } while (others[stealingStart] == this); InitializeUnderlyingThread (maxStackSize, priority); }
public ThreadWorker (IScheduler sched, ThreadWorker[] others, IProducerConsumerCollection<Task> sharedWorkQueue, bool createThread, int maxStackSize, ThreadPriority priority, EventWaitHandle handle) { this.others = others; this.dDeque = new CyclicDeque<Task> (); this.sharedWorkQueue = sharedWorkQueue; this.workerLength = others.Length; this.isLocal = !createThread; this.waitHandle = handle; this.childWorkAdder = delegate (Task t) { dDeque.PushBottom (t); sched.PulseAll (); }; // Find the stealing start index randomly (then the traversal // will be done in Round-Robin fashion) do { this.stealingStart = r.Next(0, workerLength); } while (others[stealingStart] == this); InitializeUnderlyingThread (maxStackSize, priority); }
public Scheduler (int maxWorker, int maxStackSize, ThreadPriority priority) { workQueue = new ConcurrentQueue<Task> (); workers = new ThreadWorker [maxWorker]; for (int i = 0; i < maxWorker; i++) { workers [i] = new ThreadWorker (this, workers, workQueue, maxStackSize, priority); } }
public Scheduler (int maxWorker, ThreadPriority priority) { workQueue = new ConcurrentQueue<Task> (); workers = new ThreadWorker [maxWorker]; for (int i = 0; i < maxWorker; i++) { workers [i] = new ThreadWorker (workers, i, workQueue, new CyclicDeque<Task> (), priority, pulseHandle); workers [i].Pulse (); } }
static void Main(string[] args) { Thread.Sleep(5000); Console.WriteLine("Background auto mail program started"); ThreadWorker worker = new ThreadWorker(); worker.ThreadDone += worker_ThreadDone; Console.WriteLine("Object created and method assigned..."); Thread thread1 = new Thread(worker.Run); thread1.Start(); _count = 0; }
static void worker_ThreadDone(object sender, EventArgs e) { Thread.Sleep(10000); Console.WriteLine("New thread!"); Console.WriteLine("Count: " + _count); ThreadWorker worker = new ThreadWorker(); worker.ThreadDone += worker_ThreadDone; Thread thread2 = new Thread(worker.Run); thread2.Start(); _count++; }
public ThreadWorker (ThreadWorker[] others, int workerPosition, IProducerConsumerCollection<Task> sharedWorkQueue, IConcurrentDeque<Task> dDeque, ThreadPriority priority, ManualResetEvent handle) { this.others = others; this.dDeque = dDeque; this.sharedWorkQueue = sharedWorkQueue; this.workerLength = others.Length; this.workerPosition = workerPosition; this.waitHandle = handle; this.threadPriority = priority; InitializeUnderlyingThread (); }
public ThreadWorker (IScheduler sched, ThreadWorker[] others, int workerPosition, IProducerConsumerCollection<Task> sharedWorkQueue, ThreadPriority priority, EventWaitHandle handle) { this.others = others; this.dDeque = new CyclicDeque<Task> (); this.sched = sched; this.sharedWorkQueue = sharedWorkQueue; this.workerLength = others.Length; this.workerPosition = workerPosition; this.waitHandle = handle; this.threadPriority = priority; InitializeUnderlyingThread (); }
public override bool Equals(object obj) { ThreadWorker temp = obj as ThreadWorker; return(temp == null ? false : Equals(temp)); }
public bool Equals(ThreadWorker other) { return((other == null) ? false : object.ReferenceEquals(this.dDeque, other.dDeque)); }
// Almost same as above but with an added predicate and treating one item at a time. // It's used by Scheduler Participate(...) method for special waiting case like // Task.WaitAll(someTasks) or Task.WaitAny(someTasks) // Predicate should be really fast and not blocking as it is called a good deal of time // Also, the method skip tasks that are LongRunning to avoid blocking (Task are not LongRunning by default) public static void ParticipativeWorkerMethod (Task self, ManualResetEventSlim predicateEvt, int millisecondsTimeout, IProducerConsumerCollection<Task> sharedWorkQueue, ThreadWorker[] others, ManualResetEvent evt) { const int stage1 = 5, stage2 = 0; int tries = 8; WaitHandle[] handles = null; Watch watch = Watch.StartNew (); if (millisecondsTimeout == -1) millisecondsTimeout = int.MaxValue; while (!predicateEvt.IsSet && watch.ElapsedMilliseconds < millisecondsTimeout) { Task value; // If we are in fact a normal ThreadWorker, use our own deque if (autoReference != null) { while (autoReference.dDeque.PopBottom (out value) == PopResult.Succeed && value != null) { evt.Set (); if (CheckTaskFitness (self, value)) value.Execute (autoReference.ChildWorkAdder); else { sharedWorkQueue.TryAdd (value); evt.Set (); } if (predicateEvt.IsSet || watch.ElapsedMilliseconds > millisecondsTimeout) return; } } int count = sharedWorkQueue.Count; // Dequeue only one item as we have restriction while (--count >= 0 && sharedWorkQueue.TryTake (out value) && value != null) { evt.Set (); if (CheckTaskFitness (self, value)) value.Execute (null); else { if (autoReference == null) sharedWorkQueue.TryAdd (value); else autoReference.dDeque.PushBottom (value); evt.Set (); } if (predicateEvt.IsSet || watch.ElapsedMilliseconds > millisecondsTimeout) return; } // First check to see if we comply to predicate if (predicateEvt.IsSet || watch.ElapsedMilliseconds > millisecondsTimeout) return; // Try to complete other work by stealing since our desired tasks may be in other worker ThreadWorker other; for (int i = 0; i < others.Length; i++) { if ((other = others [i]) == autoReference || other == null) continue; if (other.dDeque.PopTop (out value) == PopResult.Succeed && value != null) { evt.Set (); if (CheckTaskFitness (self, value)) value.Execute (null); else { if (autoReference == null) sharedWorkQueue.TryAdd (value); else autoReference.dDeque.PushBottom (value); evt.Set (); } } if (predicateEvt.IsSet || watch.ElapsedMilliseconds > millisecondsTimeout) return; } if (--tries > stage1) Thread.Yield (); else if (tries >= stage2) predicateEvt.Wait (ComputeTimeout (100, millisecondsTimeout, watch)); else { if (tries == stage2 - 1) handles = new [] { predicateEvt.WaitHandle, evt }; WaitHandle.WaitAny (handles, ComputeTimeout (1000, millisecondsTimeout, watch)); } } }
public ThreadWorker (IScheduler sched, ThreadWorker[] others, IProducerConsumerCollection<Task> sharedWorkQueue, int maxStackSize, ThreadPriority priority) : this (sched, others, sharedWorkQueue, true, maxStackSize, priority) { }
public bool Equals (ThreadWorker other) { return (other == null) ? false : object.ReferenceEquals (this.dDeque, other.dDeque); }
// Almost same as above but with an added predicate and treating one item at a time. // It's used by Scheduler Participate(...) method for special waiting case like // Task.WaitAll(someTasks) or Task.WaitAny(someTasks) // Predicate should be really fast and not blocking as it is called a good deal of time // Also, the method skip tasks that are LongRunning to avoid blocking (Task are not LongRunning by default) public static void WorkerMethod (Func<bool> predicate, IProducerConsumerCollection<Task> sharedWorkQueue, ThreadWorker[] others) { while (!predicate ()) { Task value; // Dequeue only one item as we have restriction if (sharedWorkQueue.TryTake (out value)) { if (value != null) { if (CheckTaskFitness (value)) value.Execute (null); else sharedWorkQueue.TryAdd (value); } } // First check to see if we comply to predicate if (predicate ()) { return; } // Try to complete other work by stealing since our desired tasks may be in other worker ThreadWorker other; for (int i = 0; i < others.Length; i++) { if ((other = others [i]) == null) continue; if (other.dDeque.PopTop (out value) == PopResult.Succeed) { if (value != null) { if (CheckTaskFitness (value)) value.Execute (null); else sharedWorkQueue.TryAdd (value); } } if (predicate ()) { return; } } } }
// Almost same as above but with an added predicate and treating one item at a time. // It's used by Scheduler Participate(...) method for special waiting case like // Task.WaitAll(someTasks) or Task.WaitAny(someTasks) // Predicate should be really fast and not blocking as it is called a good deal of time // Also, the method skip tasks that are LongRunning to avoid blocking (Task are not LongRunning by default) public static void WorkerMethod (Func<bool> predicate, IProducerConsumerCollection<Task> sharedWorkQueue, ThreadWorker[] others, ManualResetEvent evt) { while (!predicate ()) { Task value; // If we are in fact a normal ThreadWorker, use our own deque if (autoReference != null) { while (autoReference.dDeque.PopBottom (out value) == PopResult.Succeed && value != null) { evt.Set (); if (CheckTaskFitness (value)) value.Execute (autoReference.ChildWorkAdder); else { autoReference.dDeque.PushBottom (value); evt.Set (); } if (predicate ()) return; } } // Dequeue only one item as we have restriction while (sharedWorkQueue.TryTake (out value) && value != null) { evt.Set (); if (CheckTaskFitness (value)) value.Execute (null); else { sharedWorkQueue.TryAdd (value); evt.Set (); } if (predicate ()) return; } // First check to see if we comply to predicate if (predicate ()) return; // Try to complete other work by stealing since our desired tasks may be in other worker ThreadWorker other; for (int i = 0; i < others.Length; i++) { if ((other = others [i]) == null) continue; if (other.dDeque.PopTop (out value) == PopResult.Succeed && value != null) { evt.Set (); if (CheckTaskFitness (value)) value.Execute (null); else { sharedWorkQueue.TryAdd (value); evt.Set (); } } if (predicate ()) return; } Thread.Yield (); } }
// This is the actual method called in the Thread void WorkerMethodWrapper () { int sleepTime = 0; autoReference = this; // Main loop while (started == 1) { bool result = false; result = WorkerMethod (); if (!result) waitHandle.Reset (); Thread.Yield (); if (result) { deepSleepTime = 8; sleepTime = 0; continue; } // If we are spinning too much, have a deeper sleep if (++sleepTime > sleepThreshold && sharedWorkQueue.Count == 0) { waitHandle.WaitOne ((deepSleepTime = deepSleepTime >= 0x4000 ? 0x4000 : deepSleepTime << 1)); } } started = 0; }
// Called with Task.WaitAll(someTasks) or Task.WaitAny(someTasks) so that we can remove ourselves // also when our wait condition is ok public void ParticipateUntil(Func <bool> predicate) { ThreadWorker.WorkerMethod(predicate, workQueue, workers); }
internal void ParticipateUntilInternal(Task self, ManualResetEventSlim evt, int millisecondsTimeout) { ThreadWorker.ParticipativeWorkerMethod(self, evt, millisecondsTimeout, workQueue, workers, pulseHandle); }
// Almost same as above but with an added predicate and treating one item at a time. // It's used by Scheduler Participate(...) method for special waiting case like // Task.WaitAll(someTasks) or Task.WaitAny(someTasks) // Predicate should be really fast and not blocking as it is called a good deal of time // Also, the method skip tasks that are LongRunning to avoid blocking (Task are not LongRunning by default) public static void ParticipativeWorkerMethod (Task self, ManualResetEventSlim predicateEvt, int millisecondsTimeout, IProducerConsumerCollection<Task> sharedWorkQueue, ThreadWorker[] others, ManualResetEvent evt) { const int stage1 = 5, stage2 = 0; int tries = 50; WaitHandle[] handles = null; Watch watch = Watch.StartNew (); if (millisecondsTimeout == -1) millisecondsTimeout = int.MaxValue; bool aggressive = false; bool hasAutoReference = autoReference != null; Action<Task> adder = null; while (!predicateEvt.IsSet && watch.ElapsedMilliseconds < millisecondsTimeout && !self.IsCompleted) { // We try to execute the self task as it may be the simplest way to unlock // the situation if (self.Status == TaskStatus.WaitingToRun) { self.Execute (hasAutoReference ? autoReference.adder : (Action<Task>)null); if (predicateEvt.IsSet || watch.ElapsedMilliseconds > millisecondsTimeout) return; } Task value; // If we are in fact a normal ThreadWorker, use our own deque if (hasAutoReference) { var enumerable = autoReference.dDeque.GetEnumerable (); if (adder == null) adder = hasAutoReference ? autoReference.adder : (Action<Task>)null; if (enumerable != null) { foreach (var t in enumerable) { if (t == null) continue; if (CheckTaskFitness (self, t)) t.Execute (adder); if (predicateEvt.IsSet || watch.ElapsedMilliseconds > millisecondsTimeout) return; } } } int count = sharedWorkQueue.Count; // Dequeue only one item as we have restriction while (--count >= 0 && sharedWorkQueue.TryTake (out value) && value != null) { evt.Set (); if (CheckTaskFitness (self, value) || aggressive) value.Execute (null); else { if (autoReference == null) sharedWorkQueue.TryAdd (value); else autoReference.dDeque.PushBottom (value); evt.Set (); } if (predicateEvt.IsSet || watch.ElapsedMilliseconds > millisecondsTimeout) return; } // First check to see if we comply to predicate if (predicateEvt.IsSet || watch.ElapsedMilliseconds > millisecondsTimeout) return; // Try to complete other work by stealing since our desired tasks may be in other worker ThreadWorker other; for (int i = 0; i < others.Length; i++) { if ((other = others [i]) == autoReference || other == null) continue; if (other.dDeque.PopTop (out value) == PopResult.Succeed && value != null) { evt.Set (); if (CheckTaskFitness (self, value) || aggressive) value.Execute (null); else { if (autoReference == null) sharedWorkQueue.TryAdd (value); else autoReference.dDeque.PushBottom (value); evt.Set (); } } if (predicateEvt.IsSet || watch.ElapsedMilliseconds > millisecondsTimeout) return; } /* Waiting is split in 4 phases * - until stage 1 we simply yield the thread to let others add data * - between stage 1 and stage2 we use ManualResetEventSlim light waiting mechanism * - after stage2 we fall back to the heavier WaitHandle waiting mechanism * - if really the situation isn't evolving after a couple of sleep, we disable * task fitness check altogether */ if (--tries > stage1) Thread.Yield (); else if (tries >= stage2) predicateEvt.Wait (ComputeTimeout (5, millisecondsTimeout, watch)); else { if (tries == stage2 - 1) handles = new [] { predicateEvt.WaitHandle, evt }; WaitHandle.WaitAny (handles, ComputeTimeout (1000, millisecondsTimeout, watch)); if (tries == stage2 - 10) aggressive = true; } } }