private void CallbackWrapper(object state) { DispatcherItem item = (DispatcherItem)state; SendOrPostCallback userCallback = item.UserCallback; object userContext = item.UserContext; try { userCallback(userContext); } catch (Exception excp) { _Dispatcher.SetLastException(excp); _Dispatcher.Logger.Log(excp); } _Dispatcher.DecOutstanding(); // now dispatch any waiting items ProcessNode(item); }
private void ProcessNode(DispatcherItem completedItem) { long threadsInTree = IncThreadsInTree(); try { if (completedItem != null) { // completed item cleanup DecThreadsInTree(); long debugN = Interlocked.Decrement(ref _ThisNodeRunning); Debug.Assert(debugN == 0); _Parent?.DecChildrenRunning(); completedItem = null; } bool looping = true; while (looping) { looping = false; // ensure that at least one pass through the dequeuing logic occurs _Queue.Locked((queue) => { // we have the queue // we can dispatch the head of the queue if: // a) the item is for this level, AND this tree is not running; // or b) the item is for a lower level, AND this node is not running. if (queue.Count > 0) { DispatcherItem workItem = queue.Peek(); Debug.Assert(workItem.Level >= _Level); if ((workItem.Level == _Level) && (Interlocked.Add(ref _ThisNodeRunning, 0) == 0) && (Interlocked.Add(ref _ChildrenRunning, 0) == 0)) { // item is for this level // dispatch it to the threadpool queue.Dequeue(); long debugN = Interlocked.Increment(ref _ThisNodeRunning); Debug.Assert(debugN == 1); IncThreadsInTree(); ThreadPool.QueueUserWorkItem(CallbackWrapper, workItem); } if ((workItem.Level > _Level) && (Interlocked.Add(ref _ThisNodeRunning, 0) == 0)) { // item is for lower level // enqueue it to the child queue.Dequeue(); Interlocked.Increment(ref _ChildrenRunning); DispatcherNode childNode = workItem.NodeList[_Level + 1]; childNode.Enqueue(workItem); // dequeue next looping = true; } } }); } // while looping } finally { threadsInTree = DecThreadsInTree(); } if ((threadsInTree == 0) && (_Parent != null)) { // we are the last thread in this tree - handoff to parent ThreadPool.QueueUserWorkItem(_Parent.AsyncProcessNode, null); } }
internal void Enqueue(DispatcherItem item) { _Queue.Locked((queue) => queue.Enqueue(item)); ThreadPool.QueueUserWorkItem(AsyncProcessNode, null); }