/// <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 QueuedTaskSchedulerQueue 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 (int 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(QueuedTaskSchedulerQueue queue) { if (queue == null) { throw new ArgumentNullException("queue"); } _queue = queue; }
/// <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() { bool continueProcessing = true; while (!_disposeCancellation.IsCancellationRequested && continueProcessing) { try { // Until there are no more tasks to process while (!_disposeCancellation.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. QueuedTaskSchedulerQueue 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; } } } } }
/// <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() { bool flag = true; while (!this._disposeCancellation.IsCancellationRequested && flag) { try { _taskProcessingThread.Value = true; while (!this._disposeCancellation.IsCancellationRequested) { Task task; lock (this._nonthreadsafeTaskQueue) { if (this._nonthreadsafeTaskQueue.Count == 0) { break; } task = this._nonthreadsafeTaskQueue.Dequeue(); } QueuedTaskSchedulerQueue queueForTargetTask = null; if (task == null) { lock (this._queueGroups) { this.FindNextTask_NeedsLock(out task, out queueForTargetTask); } } if (task != null) { if (queueForTargetTask != null) { queueForTargetTask.ExecuteTask(task); } else { base.TryExecuteTask(task); } } } continue; } finally { lock (this._nonthreadsafeTaskQueue) { if (this._nonthreadsafeTaskQueue.Count == 0) { this._delegatesQueuedOrRunning--; flag = false; _taskProcessingThread.Value = false; } } } } }
/// <summary>Removes a scheduler from the group.</summary> /// <param name="queue">The scheduler to be removed.</param> private void RemoveQueue_NeedsLock(QueuedTaskSchedulerQueue queue) { QueueGroup group = this._queueGroups[queue._priority]; int index = group.IndexOf(queue); if (group.NextQueueIndex >= index) { group.NextQueueIndex--; } group.RemoveAt(index); }
/// <summary>Removes a scheduler from the group.</summary> /// <param name="queue">The scheduler to be removed.</param> private void RemoveQueue_NeedsLock(QueuedTaskSchedulerQueue queue) { // Find the group that contains the queue and the queue's index within the group var queueGroup = _queueGroups[queue._priority]; int 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) { QueuedTaskSchedulerQueue item = new QueuedTaskSchedulerQueue(priority, this); lock (this._queueGroups) { QueueGroup group; if (!this._queueGroups.TryGetValue(priority, out group)) { group = new QueueGroup(); this._queueGroups.Add(priority, group); } group.Add(item); } return(item); }
/// <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 QueuedTaskSchedulerQueue(priority, this); // Add the queue to the appropriate queue group based on priority lock (_queueGroups) { if (!_queueGroups.TryGetValue(priority, out QueueGroup list)) { list = new QueueGroup(); _queueGroups.Add(priority, list); } list.Add(createdQueue); } // Hand the new queue back return(createdQueue); }
/// <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 QueuedTaskSchedulerQueue queueForTargetTask) { targetTask = null; queueForTargetTask = null; foreach (KeyValuePair <int, QueueGroup> pair in this._queueGroups) { QueueGroup group = pair.Value; foreach (int num in group.CreateSearchOrder()) { queueForTargetTask = group[num]; Queue <Task> queue = queueForTargetTask._workItems; if (queue.Count > 0) { targetTask = queue.Dequeue(); if (queueForTargetTask._disposed && (queue.Count == 0)) { this.RemoveQueue_NeedsLock(queueForTargetTask); } group.NextQueueIndex = (group.NextQueueIndex + 1) % pair.Value.Count; break; } } } }
/// <summary>Initializes the debug view.</summary> /// <param name="queue">The queue to be debugged.</param> public QueuedTaskSchedulerQueueDebugView(QueuedTaskSchedulerQueue queue) { _queue = queue ?? throw new ArgumentNullException("queue"); }
public QueuedTaskSchedulerQueueDebugView(QueuedTaskSchedulerQueue queue) => _Queue = queue ?? throw new ArgumentNullException(nameof(queue));
/// <summary>Initializes the debug view.</summary> /// <param name="queue">The queue to be debugged.</param> public QueuedTaskSchedulerQueueDebugView(QueuedTaskSchedulerQueue queue) =>