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));
        }
예제 #4
0
        /// <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);
        }