private void ProcessWorkItems(object nodeObj) { // nodeObj is non-null when a thread caught an exception and had to throw, // the thread created another one and passed its node obj to us. LinkedIdleThread node = nodeObj == null ? new LinkedIdleThread(new ManualResetEventSlim(true)) : (LinkedIdleThread)nodeObj; try { while (true) { Action action; LinkedWork workNode = sharedWorkStack; if (workNode != null) { if (TryTakeFromSharedNonBlocking(out var tempAction, workNode)) { action = tempAction; } else { // We have shared work to do but failed to retrieve it, try again continue; } } else { // Should we notify system that this thread is ready to work? // This has to also work for when a thread takes the place of another one when restoring // from an exception for example. // If the mre was set and we took the work, this node definitely is dequeued, re-queue it if (node.MRE.IsSet && Volatile.Read(ref node.Work) == null) { // Notify that we're waiting for work node.MRE.Reset(); node.PreviousIsValid = false; node.Previous = Interlocked.Exchange(ref idleThreads, node); node.PreviousIsValid = true; } // Wait for work SpinWait sw = new SpinWait(); while (true) { if (node.MRE.IsSet) { // Work has been scheduled for this thread specifically, take it action = Interlocked.Exchange(ref node.Work, null); break; } if (TryTakeFromSharedNonBlocking(out var tempAction, sharedWorkStack)) { action = tempAction; break; // We successfully dequeued this node from the shared stack, quit loop and process action } // Wait for work if (sw.NextSpinWillYield) { // Wait for work to be scheduled specifically to this thread node.MRE.Wait(); action = Interlocked.Exchange(ref node.Work, null); break; } sw.SpinOnce(); } } try { action(); } finally { PooledDelegateHelper.Release(action); } } } finally { // We must keep up the amount of threads that the system handles. // Spawn a new one as this one is about to abort because of an exception. NewThread(node); } }