/// <summary>Find the next task that should be executed, based on priorities and fairness and the like.</summary>
        /// <param name="targetTask">The found task, or null if none was found.</param>
        /// <param name="queueForTargetTask">
        ///     The scheduler associated with the found task.  Due to security checks inside of TPL,
        ///     this scheduler needs to be used to execute that task.
        /// </param>
        private void FindNextTask_NeedsLock(out Task targetTask, out DistributedQueuedTaskSchedulerQueue queueForTargetTask)
        {
            targetTask         = null;
            queueForTargetTask = null;

            // Look through each of our queue groups in sorted order.
            // This ordering is based on the priority of the queues.
            foreach (var queueGroup in _queueGroups)
            {
                var queues = queueGroup.Value;

                // Within each group, iterate through the queues in a round-robin
                // fashion.  Every time we iterate again and successfully find a task,
                // we'll start in the next location in the group.
                foreach (var i in queues.CreateSearchOrder())
                {
                    queueForTargetTask = queues[i];
                    var items = queueForTargetTask._workItems;
                    if (items.Count > 0)
                    {
                        targetTask = items.Dequeue();
                        if (queueForTargetTask._disposed && items.Count == 0)
                        {
                            RemoveQueue_NeedsLock(queueForTargetTask);
                        }

                        queues.NextQueueIndex = (queues.NextQueueIndex + 1) % queueGroup.Value.Count;
                        return;
                    }
                }
            }
        }
 /// <summary>Initializes the debug view.</summary>
 /// <param name="queue">The queue to be debugged.</param>
 public QueuedTaskSchedulerQueueDebugView(DistributedQueuedTaskSchedulerQueue queue)
 {
     if (queue == null)
     {
         throw new ArgumentNullException("queue");
     }
     _queue = queue;
 }
        /// <summary>Removes a scheduler from the group.</summary>
        /// <param name="queue">The scheduler to be removed.</param>
        private void RemoveQueue_NeedsLock(DistributedQueuedTaskSchedulerQueue queue)
        {
            // Find the group that contains the queue and the queue's index within the group
            var queueGroup = _queueGroups[queue._priority];
            var index      = queueGroup.IndexOf(queue);

            // We're about to remove the queue, so adjust the index of the next
            // round-robin starting location if it'll be affected by the removal
            if (queueGroup.NextQueueIndex >= index)
            {
                queueGroup.NextQueueIndex--;
            }

            // Remove it
            queueGroup.RemoveAt(index);
        }
        /// <summary>Creates and activates a new scheduling queue for this scheduler.</summary>
        /// <param name="priority">The priority level for the new queue.</param>
        /// <returns>The newly created and activated queue at the specified priority.</returns>
        public TaskScheduler ActivateNewQueue(int priority)
        {
            // Create the queue
            var createdQueue = new DistributedQueuedTaskSchedulerQueue(priority, this);

            // Add the queue to the appropriate queue group based on priority
            lock (_queueGroups) {
                QueueGroup list;
                if (!_queueGroups.TryGetValue(priority, out list))
                {
                    list = new QueueGroup();
                    _queueGroups.Add(priority, list);
                }

                list.Add(createdQueue);
            }

            // Hand the new queue back
            return(createdQueue);
        }
        /// <summary>
        ///     Process tasks one at a time in the best order.
        ///     This should be run in a Task generated by QueueTask.
        ///     It's been separated out into its own method to show up better in Parallel Tasks.
        /// </summary>
        private void ProcessPrioritizedAndBatchedTasks()
        {
            var continueProcessing = true;

            while (!_sharedCancellation.IsCancellationRequested && continueProcessing)
            {
                try {
                    // Note that we're processing tasks on this thread
                    _taskProcessingThread.Value = true;

                    // Until there are no more tasks to process
                    while (!_sharedCancellation.IsCancellationRequested)
                    {
                        // Try to get the next task.  If there aren't any more, we're done.
                        Task targetTask;
                        lock (_nonthreadsafeTaskQueue) {
                            if (_nonthreadsafeTaskQueue.Count == 0)
                            {
                                break;
                            }
                            targetTask = _nonthreadsafeTaskQueue.Dequeue();
                        }

                        // If the task is null, it's a placeholder for a task in the round-robin queues.
                        // Find the next one that should be processed.
                        DistributedQueuedTaskSchedulerQueue queueForTargetTask = null;
                        if (targetTask == null)
                        {
                            lock (_queueGroups) {
                                FindNextTask_NeedsLock(out targetTask, out queueForTargetTask);
                            }
                        }

                        // Now if we finally have a task, run it.  If the task
                        // was associated with one of the round-robin schedulers, we need to use it
                        // as a thunk to execute its task.
                        if (targetTask != null)
                        {
                            if (queueForTargetTask != null)
                            {
                                queueForTargetTask.ExecuteTask(targetTask);
                            }
                            else
                            {
                                TryExecuteTask(targetTask);
                            }
                        }
                    }
                } finally {
                    // Now that we think we're done, verify that there really is
                    // no more work to do.  If there's not, highlight
                    // that we're now less parallel than we were a moment ago.
                    lock (_nonthreadsafeTaskQueue) {
                        if (_nonthreadsafeTaskQueue.Count == 0)
                        {
                            _delegatesQueuedOrRunning--;
                            continueProcessing          = false;
                            _taskProcessingThread.Value = false;
                        }
                    }
                }
            }
        }