private void Process(object state) { // Cast the input to the right object var args = (Tuple <TaskCompletionSource <object>, Task>)state; // Process all the input TConsume consume; while (!_hasError && Consume.TryTake(out consume)) { try { ProcessConsume(consume); } catch (Exception e) { // Let other threads know of the error _hasError = true; // Inform the task of the exception args.Item1.TrySetException(e); } } // Determine if this is the last thread to complete var completedThreads = Interlocked.Increment(ref _completedThreads); if (completedThreads < ThreadCount) { return; } // Complete the production collection _produce.CompleteAdding(); if (args.Item2 != null) { // Now wait for the producing task to complete // It should already be done but we need to collect any exceptions try { args.Item2.Wait(); } catch (Exception e) { // There was an exception in a dependent task args.Item1.TrySetException(e); } } // Notify the handle that this is done args.Item1.TrySetResult(null); }