public void Enqueue(IHeliosWorkItem callback, bool forceGlobal) { ThreadPoolWorkQueueThreadLocals tl = null; if (!forceGlobal) { tl = ThreadPoolWorkQueueThreadLocals.threadLocals; } if (null != tl) { tl.workStealingQueue.LocalPush(callback); } else { QueueSegment head = queueHead; while (!head.TryEnqueue(callback)) { Interlocked.CompareExchange(ref head.Next, new QueueSegment(), null); while (head.Next != null) { Interlocked.CompareExchange(ref queueHead, head.Next, head); head = queueHead; } } } }
public void Dequeue(ThreadPoolWorkQueueThreadLocals tl, out IHeliosWorkItem callback, out bool missedSteal) { callback = null; missedSteal = false; WorkStealingQueue wsq = tl.workStealingQueue; if (wsq.LocalPop(out callback)) { Contract.Assert(null != callback); } if (null == callback) { QueueSegment tail = queueTail; while (true) { if (tail.TryDequeue(out callback)) { Contract.Assert(null != callback); break; } if (null == tail.Next || !tail.IsUsedUp()) { break; } else { Interlocked.CompareExchange(ref queueTail, tail.Next, tail); tail = queueTail; } } } if (null == callback) { WorkStealingQueue[] otherQueues = allThreadQueues.Current; int i = tl.random.Next(otherQueues.Length); int c = otherQueues.Length; while (c > 0) { WorkStealingQueue otherQueue = Volatile.Read(ref otherQueues[i % otherQueues.Length]); if (otherQueue != null && otherQueue != wsq && otherQueue.TrySteal(out callback, ref missedSteal)) { Contract.Assert(null != callback); break; } i++; c--; } } }
internal bool LocalFindAndPop(IHeliosWorkItem callback) { ThreadPoolWorkQueueThreadLocals tl = ThreadPoolWorkQueueThreadLocals.threadLocals; if (null == tl) { return(false); } return(tl.workStealingQueue.LocalFindAndPop(callback)); }
/// <summary> /// Method run internally by each worker thread /// </summary> private bool Dispatch() { var workQueue = WorkQueue; // // Update our records to indicate that an outstanding request for a thread has now been fulfilled. // From this point on, we are responsible for requesting another thread if we stop working for any // reason, and we believe there might still be work in the queue. MarkThreadRequestSatisfied(); bool needAnotherThread = true; IHeliosWorkItem workItem = null; try { //Set up thread-local data ThreadPoolWorkQueueThreadLocals tl = workQueue.EnsureCurrentThreadHasQueue(); while (!_shutdownRequested && tl.ConsecutiveQueueMissCount < workQueue.QueueMissUpperLimit) //look for work until explicitly shut down or too many queue misses { bool missedSteal = false; workQueue.Dequeue(tl, out workItem, out missedSteal); try { } finally { if (workItem == null) { // // No work. We're going to return to the VM once we leave this protected region. // If we missed a steal, though, there may be more work in the queue. // Instead of looping around and trying again, we'll just request another thread. This way // we won't starve other AppDomains while we spin trying to get locks, and hopefully the thread // that owns the contended work-stealing queue will pick up its own workitems in the meantime, // which will be more efficient than this thread doing it anyway. // needAnotherThread = missedSteal; } else { // // If we found work, there may be more work. Ask for another thread so that the other work can be processed // in parallel. Note that this will only ask for a max of #procs threads, so it's safe to call it for every dequeue. // EnsureThreadRequested(); } } if (workItem == null) { tl.IncrementQueueMiss(); } else //execute our work { tl.ResetQueueMiss(); workItem.ExecuteWorkItem(); workItem = null; } } return(true); } finally { //had an exception in the course of executing some work, and this thread is going to die. if (needAnotherThread) { EnsureThreadRequested(); } } //should never hit this code, unless something catastrophically bad happened (like an aborted thread) Contract.Assert(false); return(true); }