Beispiel #1
0
        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);
            }
        }