public Task ProduceTasksAsync(int numberOfTasks) { ManualResetEvent bufferSpaceAvailableWaitHandle = new ManualResetEvent(false); Queue <Type> taskPayloadTypes = new Queue <Type>(mPayloadTypes); return(Task.Run(() => { Type currentPayloadType; IQueuedTaskToken newTaskToken; QueuedTask newTask; QueuedTaskResult newLastTaskResult; EventHandler handleBufferElementRemoved = (s, e) => bufferSpaceAvailableWaitHandle.Set(); mTaskBuffer.QueuedTaskRetrieved += handleBufferElementRemoved; while (taskPayloadTypes.TryDequeue(out currentPayloadType)) { for (int i = 0; i < numberOfTasks; i++) { newTask = new QueuedTask(Guid.NewGuid()) { Payload = Activator.CreateInstance(currentPayloadType), Type = currentPayloadType.FullName }; newLastTaskResult = new QueuedTaskResult(newTask) { Status = QueuedTaskStatus.Unprocessed }; newTaskToken = new MockQueuedTaskToken(newTask, newLastTaskResult); mProducedTasks.Add(newTaskToken); while (!mTaskBuffer.TryAddNewTask(newTaskToken)) { bufferSpaceAvailableWaitHandle.WaitOne(); bufferSpaceAvailableWaitHandle.Reset(); } } } mTaskBuffer.CompleteAdding(); mTaskBuffer.QueuedTaskRetrieved -= handleBufferElementRemoved; })); }
private async Task PollForQueuedTasksAsync() { CancellationToken stopToken = mStopTokenSource .Token; //Check cancellation token before starting // the polling loop if (stopToken.IsCancellationRequested) { return; } while (true) { try { //Check for token cancellation at the beginning of the loop stopToken.ThrowIfCancellationRequested(); //If the buffer is full, we wait for some space to become available, // since, even if we can dequeue an task, // we won't have anywhere to place it yet and we // may be needlessly helding a lock to that task if (mTaskBuffer.IsFull) { mLogger.Debug("Task buffer is full. Waiting for available space..."); mMetrics.UpdateMetric(AppMetricId.PollerWaitForBufferSpaceCount, m => m.Increment()); await mWaitForClearToAddToBuffer.ToTask(); } //It may be that the wait handle was signaled // as part of the Stop operation, // so we need to check for that as well. stopToken.ThrowIfCancellationRequested(); //Attempt to dequeue and then check cancellation IQueuedTaskToken queuedTaskToken = await mTaskQueueConsumer .DequeueAsync(mRequiredPayloadTypes); //Before posting the token to the buffer, // check if cancellation was requested stopToken.ThrowIfCancellationRequested(); if (queuedTaskToken != null) { //If we have found a token, attempt to set it as started // and only then add it to buffer for processing. //If not, dispose and discard the token mLogger.DebugFormat("Task found with id = {0}, type = {1}. Acquiring reservation...", queuedTaskToken.DequeuedTask.Id, queuedTaskToken.DequeuedTask.Type); mMetrics.UpdateMetric(AppMetricId.PollerDequeueCount, m => m.Increment()); mTaskBuffer.TryAddNewTask(queuedTaskToken); } else { //If there is no task available in the queue, begin waiting for // a notification of new added tasks mLogger.Debug("No task dequeued when polled. Waiting for available task..."); mMetrics.UpdateMetric(AppMetricId.PollerWaitForDequeueCount, m => m.Increment()); await mWaitForClearToDequeue.ToTask(); } //It may be that the wait handle was signaled // as part of the Stop operation, // so we need to check for that as well. stopToken.ThrowIfCancellationRequested(); //Finally, reset all the handles, at the end of the loop mWaitForClearToAddToBuffer.Reset(); mWaitForClearToDequeue.Reset(); } catch (OperationCanceledException) { mLogger.Debug("Stop requested. Breaking polling loop..."); break; } } mTaskBuffer.CompleteAdding(); }