public void Enqueue(IThreadPoolWorkItem callback, bool forceGlobal) { ThreadPoolWorkQueueThreadLocals queueThreadLocals = (ThreadPoolWorkQueueThreadLocals)null; if (!forceGlobal) { queueThreadLocals = ThreadPoolWorkQueueThreadLocals.threadLocals; } if (this.loggingEnabled) { FrameworkEventSource.Log.ThreadPoolEnqueueWorkObject((object)callback); } if (queueThreadLocals != null) { queueThreadLocals.workStealingQueue.LocalPush(callback); } else { ThreadPoolWorkQueue.QueueSegment comparand = this.queueHead; while (!comparand.TryEnqueue(callback)) { Interlocked.CompareExchange <ThreadPoolWorkQueue.QueueSegment>(ref comparand.Next, new ThreadPoolWorkQueue.QueueSegment(), (ThreadPoolWorkQueue.QueueSegment)null); for (; comparand.Next != null; comparand = this.queueHead) { Interlocked.CompareExchange <ThreadPoolWorkQueue.QueueSegment>(ref this.queueHead, comparand.Next, comparand); } } } this.EnsureThreadRequested(); }
public void Enqueue(IThreadPoolWorkItem callback, bool forceGlobal) { ThreadPoolWorkQueueThreadLocals threadLocals = null; if (!forceGlobal) { threadLocals = ThreadPoolWorkQueueThreadLocals.threadLocals; } if (threadLocals != null) { threadLocals.workStealingQueue.LocalPush(callback); } else { QueueSegment queueHead = this.queueHead; while (!queueHead.TryEnqueue(callback)) { Interlocked.CompareExchange <QueueSegment>(ref queueHead.Next, new QueueSegment(), null); while (queueHead.Next != null) { Interlocked.CompareExchange <QueueSegment>(ref this.queueHead, queueHead.Next, queueHead); queueHead = this.queueHead; } } } this.EnsureThreadRequested(); }
public void Dequeue(ThreadPoolWorkQueueThreadLocals tl, out IThreadPoolWorkItem callback, out bool missedSteal) { callback = null; missedSteal = false; WorkStealingQueue workStealingQueue = tl.workStealingQueue; workStealingQueue.LocalPop(out callback); if (callback == null) { for (QueueSegment segment = this.queueTail; (!segment.TryDequeue(out callback) && (segment.Next != null)) && segment.IsUsedUp(); segment = this.queueTail) { Interlocked.CompareExchange <QueueSegment>(ref this.queueTail, segment.Next, segment); } } if (callback == null) { WorkStealingQueue[] current = allThreadQueues.Current; int num = tl.random.Next(current.Length); for (int i = current.Length; i > 0; i--) { WorkStealingQueue queue2 = current[num % current.Length]; if (((queue2 != null) && (queue2 != workStealingQueue)) && queue2.TrySteal(out callback, ref missedSteal)) { return; } num++; } } }
public void Dequeue(ThreadPoolWorkQueueThreadLocals tl, out IThreadPoolWorkItem callback, out bool missedSteal) { callback = (IThreadPoolWorkItem)null; missedSteal = false; ThreadPoolWorkQueue.WorkStealingQueue workStealingQueue1 = tl.workStealingQueue; workStealingQueue1.LocalPop(out callback); if (callback == null) { for (ThreadPoolWorkQueue.QueueSegment comparand = this.queueTail; !comparand.TryDequeue(out callback) && comparand.Next != null && comparand.IsUsedUp(); comparand = this.queueTail) { Interlocked.CompareExchange <ThreadPoolWorkQueue.QueueSegment>(ref this.queueTail, comparand.Next, comparand); } } if (callback != null) { return; } ThreadPoolWorkQueue.WorkStealingQueue[] current = ThreadPoolWorkQueue.allThreadQueues.Current; int num = tl.random.Next(current.Length); for (int length = current.Length; length > 0; --length) { ThreadPoolWorkQueue.WorkStealingQueue workStealingQueue2 = Volatile.Read <ThreadPoolWorkQueue.WorkStealingQueue>(ref current[num % current.Length]); if (workStealingQueue2 != null && workStealingQueue2 != workStealingQueue1 && workStealingQueue2.TrySteal(out callback, ref missedSteal)) { break; } ++num; } }
public IThreadPoolWorkItem Dequeue(ThreadPoolWorkQueueThreadLocals tl, ref bool missedSteal) { WorkStealingQueue localWsq = tl.workStealingQueue; IThreadPoolWorkItem callback; if ((callback = localWsq.LocalPop()) == null && // first try the local queue !workItems.TryDequeue(out callback)) // then try the global queue { // finally try to steal from another thread's local queue WorkStealingQueue[] queues = WorkStealingQueueList.Queues; int c = queues.Length; Debug.Assert(c > 0, "There must at least be a queue for this thread."); int maxIndex = c - 1; int i = tl.random.Next(c); while (c > 0) { i = (i < maxIndex) ? i + 1 : 0; WorkStealingQueue otherQueue = queues[i]; if (otherQueue != localWsq && otherQueue.CanSteal) { callback = otherQueue.TrySteal(ref missedSteal); if (callback != null) { break; } } c--; } } return(callback); }
public void Enqueue(IThreadPoolWorkItem callback, bool forceGlobal) { ThreadPoolWorkQueueThreadLocals tl = null; if (!forceGlobal) { tl = ThreadPoolWorkQueueThreadLocals.threadLocals; } if (null != tl) { tl.workStealingQueue.LocalPush(callback); // We must guarantee wsqActive is set to WsqNowActive after we push // The ordering must be global because we rely on other threads // observing in this order Interlocked.MemoryBarrier(); // We do not want to simply write. We want to prevent unnecessary writes // which would invalidate reader's caches if (WorkStealingQueueList.wsqActive != WorkStealingQueueList.WsqNowActive) { Volatile.Write(ref WorkStealingQueueList.wsqActive, WorkStealingQueueList.WsqNowActive); } } else { workItems.Enqueue(callback); } EnsureThreadRequested(); }
public void Enqueue(IThreadPoolWorkItem callback, bool forceGlobal) { ThreadPoolWorkQueueThreadLocals tl = null; if (!forceGlobal) { tl = ThreadPoolWorkQueueThreadLocals.Current; } 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; } } } EnsureThreadRequested(); }
public void Dequeue(ThreadPoolWorkQueueThreadLocals tl, out IThreadPoolWorkItem callback, out bool missedSteal) { callback = null; missedSteal = false; ThreadPoolWorkQueue.WorkStealingQueue workStealingQueue = tl.workStealingQueue; workStealingQueue.LocalPop(out callback); if (callback == null) { ThreadPoolWorkQueue.QueueSegment queueSegment = this.queueTail; while (!queueSegment.TryDequeue(out callback) && queueSegment.Next != null && queueSegment.IsUsedUp()) { Interlocked.CompareExchange <ThreadPoolWorkQueue.QueueSegment>(ref this.queueTail, queueSegment.Next, queueSegment); queueSegment = this.queueTail; } } if (callback == null) { ThreadPoolWorkQueue.WorkStealingQueue[] array = ThreadPoolWorkQueue.allThreadQueues.Current; int num = tl.random.Next(array.Length); for (int i = array.Length; i > 0; i--) { ThreadPoolWorkQueue.WorkStealingQueue workStealingQueue2 = Volatile.Read <ThreadPoolWorkQueue.WorkStealingQueue>(ref array[num % array.Length]); if (workStealingQueue2 != null && workStealingQueue2 != workStealingQueue && workStealingQueue2.TrySteal(out callback, ref missedSteal)) { break; } num++; } } }
public void Enqueue(IThreadPoolWorkItem callback, bool forceGlobal) { ThreadPoolWorkQueueThreadLocals threadPoolWorkQueueThreadLocals = null; if (!forceGlobal) { threadPoolWorkQueueThreadLocals = ThreadPoolWorkQueueThreadLocals.threadLocals; } if (this.loggingEnabled) { FrameworkEventSource.Log.ThreadPoolEnqueueWorkObject(callback); } if (threadPoolWorkQueueThreadLocals != null) { threadPoolWorkQueueThreadLocals.workStealingQueue.LocalPush(callback); } else { ThreadPoolWorkQueue.QueueSegment queueSegment = this.queueHead; while (!queueSegment.TryEnqueue(callback)) { Interlocked.CompareExchange <ThreadPoolWorkQueue.QueueSegment>(ref queueSegment.Next, new ThreadPoolWorkQueue.QueueSegment(), null); while (queueSegment.Next != null) { Interlocked.CompareExchange <ThreadPoolWorkQueue.QueueSegment>(ref this.queueHead, queueSegment.Next, queueSegment); queueSegment = this.queueHead; } } } this.EnsureThreadRequested(); }
public IThreadPoolWorkItem Dequeue(ThreadPoolWorkQueueThreadLocals tl, ref bool missedSteal) { IThreadPoolWorkItem callback; int wsqActiveObserved = WorkStealingQueueList.wsqActive; if (wsqActiveObserved > 0) { WorkStealingQueue localWsq = tl.workStealingQueue; if ((callback = localWsq.LocalPop()) == null && // first try the local queue !workItems.TryDequeue(out callback)) // then try the global queue { // finally try to steal from another thread's local queue WorkStealingQueue[] queues = WorkStealingQueueList.Queues; int c = queues.Length; Debug.Assert(c > 0, "There must at least be a queue for this thread."); int maxIndex = c - 1; int i = tl.random.Next(c); while (c > 0) { i = (i < maxIndex) ? i + 1 : 0; WorkStealingQueue otherQueue = queues[i]; if (otherQueue != localWsq && otherQueue.CanSteal) { callback = otherQueue.TrySteal(ref missedSteal); if (callback != null) { break; } } c--; } if ((callback == null) && !missedSteal) { // Only decrement if the value is unchanged since we started looking for work // This prevents multiple threads decrementing based on overlapping scans. // // When we decrement from active, the producer may have inserted a queue item during our scan // therefore we cannot transition to empty // // When we decrement from Maybe Inactive, if the producer inserted a queue item during our scan, // the producer must write Active. We may transition to empty briefly if we beat the // producer's write, but the producer will then overwrite us before waking threads. // So effectively we cannot mark the queue empty when an item is in the queue. Interlocked.CompareExchange(ref WorkStealingQueueList.wsqActive, wsqActiveObserved - 1, wsqActiveObserved); } } } else { // We only need to look at the global queue since WorkStealingQueueList is inactive workItems.TryDequeue(out callback); } return(callback); }
internal bool LocalFindAndPop(IThreadPoolWorkItem callback) { ThreadPoolWorkQueueThreadLocals queueThreadLocals = ThreadPoolWorkQueueThreadLocals.threadLocals; if (queueThreadLocals == null) { return(false); } return(queueThreadLocals.workStealingQueue.LocalFindAndPop(callback)); }
public void Dequeue(ThreadPoolWorkQueueThreadLocals tl, out IThreadPoolWorkItem callback, out bool missedSteal) { callback = null; missedSteal = false; WorkStealingQueue wsq = tl.workStealingQueue; if (wsq.LocalPop(out callback)) { Debug.Assert(null != callback); } if (null == callback) { QueueSegment tail = queueTail; while (true) { if (tail.TryDequeue(out callback)) { Debug.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)) { Debug.Assert(null != callback); break; } i++; c--; } } }
internal bool LocalFindAndPop(IThreadPoolWorkItem callback) { ThreadPoolWorkQueueThreadLocals tl = ThreadPoolWorkQueueThreadLocals.Current; if (null == tl) { return(false); } return(tl.workStealingQueue.LocalFindAndPop(callback)); }
public void Enqueue(IThreadPoolWorkItem callback, bool forceGlobal) { ThreadPoolWorkQueueThreadLocals tl = null; if (!forceGlobal) { tl = ThreadPoolWorkQueueThreadLocals.threadLocals; } if (null != tl) { tl.workStealingQueue.LocalPush(callback); } else { workItems.Enqueue(callback); } EnsureThreadRequested(); }
public void Enqueue(IThreadPoolWorkItem callback, bool forceGlobal) { ThreadPoolWorkQueueThreadLocals tl = null; if (!forceGlobal) { tl = ThreadPoolWorkQueueThreadLocals.Current; } #if !FEATURE_CORECLR //if (loggingEnabled) // System.Diagnostics.Tracing.FrameworkEventSource.Log.ThreadPoolEnqueueWorkObject(callback); #endif 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; } } } EnsureThreadRequested(); }
/// <summary> /// Dispatches work items to this thread. /// </summary> /// <returns> /// <c>true</c> if this thread did as much work as was available or its quantum expired. /// <c>false</c> if this thread stopped working early. /// </returns> internal static bool Dispatch() { var workQueue = ThreadPoolGlobals.workQueue; // // Save the start time // int startTickCount = Environment.TickCount; // // 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. // workQueue.MarkThreadRequestSatisfied(); Interlocked.Increment(ref workQueue.numWorkingThreads); // // Assume that we're going to need another thread if this one returns to the VM. We'll set this to // false later, but only if we're absolutely certain that the queue is empty. // bool needAnotherThread = true; IThreadPoolWorkItem workItem = null; try { // // Set up our thread-local data // ThreadPoolWorkQueueThreadLocals tl = workQueue.EnsureCurrentThreadHasQueue(); // // Loop until our quantum expires or there is no work. // while (ThreadPool.KeepDispatching(startTickCount)) { bool missedSteal = false; workItem = workQueue.Dequeue(tl, ref missedSteal); if (workItem == null) { // // No work. // 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. 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; // Tell the VM we're returning normally, not because Hill Climbing asked us to return. return(true); } // // 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. // workQueue.EnsureThreadRequested(); try { SynchronizationContext.SetSynchronizationContext(null); workItem.ExecuteWorkItem(); } finally { workItem = null; SynchronizationContext.SetSynchronizationContext(null); } RuntimeThread.CurrentThread.ResetThreadPoolThread(); if (!ThreadPool.NotifyWorkItemComplete()) { return(false); } } // If we get here, it's because our quantum expired. return(true); } catch (Exception e) { // Work items should not allow exceptions to escape. For example, Task catches and stores any exceptions. Environment.FailFast("Unhandled exception in ThreadPool dispatch loop", e); return(true); // Will never actually be executed because Environment.FailFast doesn't return } finally { int numWorkers = Interlocked.Decrement(ref workQueue.numWorkingThreads); Debug.Assert(numWorkers >= 0); // // If we are exiting for any reason other than that the queue is definitely empty, ask for another // thread to pick up where we left off. // if (needAnotherThread) { workQueue.EnsureThreadRequested(); } } }
internal bool LocalFindAndPop(IThreadPoolWorkItem callback) { ThreadPoolWorkQueueThreadLocals tl = ThreadPoolWorkQueueThreadLocals.threadLocals; return(tl != null && tl.workStealingQueue.LocalFindAndPop(callback)); }
internal static bool Dispatch() { ThreadPoolWorkQueue threadPoolWorkQueue = ThreadPoolGlobals.workQueue; int tickCount = Environment.TickCount; threadPoolWorkQueue.MarkThreadRequestSatisfied(); threadPoolWorkQueue.loggingEnabled = FrameworkEventSource.Log.IsEnabled(EventLevel.Verbose, (EventKeywords)18); bool flag1 = true; IThreadPoolWorkItem callback = (IThreadPoolWorkItem)null; try { ThreadPoolWorkQueueThreadLocals tl = threadPoolWorkQueue.EnsureCurrentThreadHasQueue(); while ((long)(Environment.TickCount - tickCount) < (long)ThreadPoolGlobals.tpQuantum) { try { } finally { bool missedSteal = false; threadPoolWorkQueue.Dequeue(tl, out callback, out missedSteal); if (callback == null) { flag1 = missedSteal; } else { threadPoolWorkQueue.EnsureThreadRequested(); } } if (callback == null) { return(true); } if (threadPoolWorkQueue.loggingEnabled) { FrameworkEventSource.Log.ThreadPoolDequeueWorkObject((object)callback); } if (ThreadPoolGlobals.enableWorkerTracking) { bool flag2 = false; try { try { } finally { ThreadPool.ReportThreadStatus(true); flag2 = true; } callback.ExecuteWorkItem(); callback = (IThreadPoolWorkItem)null; } finally { if (flag2) { ThreadPool.ReportThreadStatus(false); } } } else { callback.ExecuteWorkItem(); callback = (IThreadPoolWorkItem)null; } if (!ThreadPool.NotifyWorkItemComplete()) { return(false); } } return(true); } catch (ThreadAbortException ex) { if (callback != null) { callback.MarkAborted(ex); } flag1 = false; } finally { if (flag1) { threadPoolWorkQueue.EnsureThreadRequested(); } } return(true); }
static internal void Dispatch() { var workQueue = ThreadPoolGlobals.workQueue; // // The clock is ticking! We have ThreadPoolGlobals.tpQuantum milliseconds to get some work done, and then // we need to return to the VM. // int quantumStartTime = Environment.TickCount; // // 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. // // Note that if this thread is aborted before we get a chance to request another one, the VM will // record a thread request on our behalf. So we don't need to worry about getting aborted right here. // workQueue.MarkThreadRequestSatisfied(); #if !FEATURE_CORECLR // Has the desire for logging changed since the last time we entered? //workQueue.loggingEnabled = System.Diagnostics.Tracing.FrameworkEventSource.Log.IsEnabled(System.Diagnostics.Tracing.EventLevel.Verbose, System.Diagnostics.Tracing.FrameworkEventSource.Keywords.ThreadPool); #endif // // Assume that we're going to need another thread if this one returns to the VM. We'll set this to // false later, but only if we're absolutely certain that the queue is empty. // bool needAnotherThread = true; IThreadPoolWorkItem workItem = null; try { // // Set up our thread-local data // ThreadPoolWorkQueueThreadLocals tl = workQueue.EnsureCurrentThreadHasQueue(); // // Loop until our quantum expires. // while ((Environment.TickCount - quantumStartTime) < tpQuantum) { // // Dequeue and EnsureThreadRequested must be protected from ThreadAbortException. // These are fast, so this will not delay aborts/AD-unloads for very long. // try { } finally { bool missedSteal = false; workQueue.Dequeue(tl, out workItem, out missedSteal); 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. // workQueue.EnsureThreadRequested(); } } if (workItem == null) { // no more work to do return; } else { #if !FEATURE_CORECLR //if (workQueue.loggingEnabled) // System.Diagnostics.Tracing.FrameworkEventSource.Log.ThreadPoolDequeueWorkObject(workItem); #endif // // Execute the workitem outside of any finally blocks, so that it can be aborted if needed. // //RuntimeHelpers.PrepareConstrainedRegions(); try { SynchronizationContext.SetSynchronizationContext(null); workItem.ExecuteWorkItem(); } finally { workItem = null; SynchronizationContext.SetSynchronizationContext(null); } } } } catch (Exception e) { // Work items should not allow exceptions to escape. For example, Task catches and stores any exceptions. Environment.FailFast("Unhandled exception in ThreadPool dispatch loop", e); } finally { // // If we are exiting for any reason other than that the queue is definitely empty, ask for another // thread to pick up where we left off. // if (needAnotherThread) { workQueue.EnsureThreadRequested(); } } }
internal static bool Dispatch() { ThreadPoolWorkQueue workQueue = ThreadPoolGlobals.workQueue; int tickCount = Environment.TickCount; workQueue.MarkThreadRequestSatisfied(); workQueue.loggingEnabled = FrameworkEventSource.Log.IsEnabled(EventLevel.Verbose, (EventKeywords)18L); bool flag = true; IThreadPoolWorkItem threadPoolWorkItem = null; try { ThreadPoolWorkQueueThreadLocals tl = workQueue.EnsureCurrentThreadHasQueue(); while ((long)(Environment.TickCount - tickCount) < (long)((ulong)ThreadPoolGlobals.tpQuantum)) { try { } finally { bool flag2 = false; workQueue.Dequeue(tl, out threadPoolWorkItem, out flag2); if (threadPoolWorkItem == null) { flag = flag2; } else { workQueue.EnsureThreadRequested(); } } if (threadPoolWorkItem == null) { return(true); } if (workQueue.loggingEnabled) { FrameworkEventSource.Log.ThreadPoolDequeueWorkObject(threadPoolWorkItem); } if (ThreadPoolGlobals.enableWorkerTracking) { bool flag3 = false; try { try { } finally { ThreadPool.ReportThreadStatus(true); flag3 = true; } threadPoolWorkItem.ExecuteWorkItem(); threadPoolWorkItem = null; goto IL_A6; } finally { if (flag3) { ThreadPool.ReportThreadStatus(false); } } goto IL_9E; } goto IL_9E; IL_A6: if (!ThreadPool.NotifyWorkItemComplete()) { return(false); } continue; IL_9E: threadPoolWorkItem.ExecuteWorkItem(); threadPoolWorkItem = null; goto IL_A6; } return(true); } catch (ThreadAbortException tae) { if (threadPoolWorkItem != null) { threadPoolWorkItem.MarkAborted(tae); } flag = false; } finally { if (flag) { workQueue.EnsureThreadRequested(); } } return(true); }
internal static void Dispatch() { var workQueue = ThreadPoolGlobals.workQueue; // // The clock is ticking! We have ThreadPoolGlobals.tpQuantum milliseconds to get some work done, and then // we need to return to the VM. // int quantumStartTime = Environment.TickCount; // // 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. // workQueue.MarkThreadRequestSatisfied(); // // Assume that we're going to need another thread if this one returns to the VM. We'll set this to // false later, but only if we're absolutely certain that the queue is empty. // bool needAnotherThread = true; IThreadPoolWorkItem workItem = null; try { // // Set up our thread-local data // ThreadPoolWorkQueueThreadLocals tl = workQueue.EnsureCurrentThreadHasQueue(); // // Loop until our quantum expires. // while ((Environment.TickCount - quantumStartTime) < tpQuantum) { bool missedSteal = false; workQueue.Dequeue(tl, out workItem, out missedSteal); 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; return; } // // 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. // workQueue.EnsureThreadRequested(); try { SynchronizationContext.SetSynchronizationContext(null); workItem.ExecuteWorkItem(); } finally { workItem = null; SynchronizationContext.SetSynchronizationContext(null); } } } catch (Exception e) { // Work items should not allow exceptions to escape. For example, Task catches and stores any exceptions. Environment.FailFast("Unhandled exception in ThreadPool dispatch loop", e); } finally { // // If we are exiting for any reason other than that the queue is definitely empty, ask for another // thread to pick up where we left off. // if (needAnotherThread) { workQueue.EnsureThreadRequested(); } } }
internal static bool Dispatch() { bool flag4; int tickCount = Environment.TickCount; ThreadPoolGlobals.workQueue.MarkThreadRequestSatisfied(); bool flag = true; IThreadPoolWorkItem callback = null; try { ThreadPoolWorkQueueThreadLocals tl = ThreadPoolGlobals.workQueue.EnsureCurrentThreadHasQueue(); while ((Environment.TickCount - tickCount) < ThreadPoolGlobals.tpQuantum) { try { } finally { bool missedSteal = false; ThreadPoolGlobals.workQueue.Dequeue(tl, out callback, out missedSteal); if (callback == null) { flag = missedSteal; } else { ThreadPoolGlobals.workQueue.EnsureThreadRequested(); } } if (callback == null) { return(true); } if (ThreadPoolGlobals.enableWorkerTracking) { bool flag3 = false; try { try { } finally { ThreadPool.ReportThreadStatus(true); flag3 = true; } callback.ExecuteWorkItem(); callback = null; } finally { if (flag3) { ThreadPool.ReportThreadStatus(false); } } } else { callback.ExecuteWorkItem(); callback = null; } if (!ThreadPool.NotifyWorkItemComplete()) { return(false); } } flag4 = true; } catch (ThreadAbortException exception) { if (callback != null) { callback.MarkAborted(exception); } flag = false; throw; } finally { if (flag) { ThreadPoolGlobals.workQueue.EnsureThreadRequested(); } } return(flag4); }