/// <summary> /// Creates and begins execution of a new set of spooling tasks. /// </summary> public static void Spool( QueryTaskGroupState groupState, PartitionedStream <TOutput, TKey> partitions, bool[] consumerWaiting, bool[] producerWaiting, bool[] producerDone, Queue <Pair <TKey, TOutput> >[] buffers, object[] bufferLocks, TaskScheduler taskScheduler, bool autoBuffered) { Contract.Requires(groupState != null); Contract.Requires(partitions != null); Contract.Requires(producerDone != null && producerDone.Length == partitions.PartitionCount); Contract.Requires(buffers != null && buffers.Length == partitions.PartitionCount); Contract.Requires(bufferLocks != null); int degreeOfParallelism = partitions.PartitionCount; // Initialize the buffers and buffer locks. for (int i = 0; i < degreeOfParallelism; i++) { buffers[i] = new Queue <Pair <TKey, TOutput> >(OrderPreservingPipeliningMergeHelper <TOutput, TKey> .INITIAL_BUFFER_SIZE); bufferLocks[i] = new object(); } // Ensure all tasks in this query are parented under a common root. Because this // is a pipelined query, we detach it from the parent (to avoid blocking the calling // thread), and run the query on a separate thread. Task rootTask = new Task( () => { for (int i = 0; i < degreeOfParallelism; i++) { QueryTask asyncTask = new OrderPreservingPipeliningSpoolingTask <TOutput, TKey>( partitions[i], groupState, consumerWaiting, producerWaiting, producerDone, i, buffers, bufferLocks[i], taskScheduler, autoBuffered); asyncTask.RunAsynchronously(taskScheduler); } }); // Begin the query on the calling thread. groupState.QueryBegin(rootTask); // And schedule it for execution. This is done after beginning to ensure no thread tries to // end the query before its root task has been recorded properly. rootTask.Start(taskScheduler); // We don't call QueryEnd here; when we return, the query is still executing, and the // last enumerator to be disposed of will call QueryEnd for us. }
//----------------------------------------------------------------------------------- // Schedules execution of the merge itself. // void IMergeHelper <TOutput> .Execute() { OrderPreservingPipeliningSpoolingTask <TOutput, TKey> .Spool( m_taskGroupState, m_partitions, m_consumerWaiting, m_producerWaiting, m_producerDone, m_buffers, m_bufferLocks, m_taskScheduler, m_autoBuffered); }