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);
        }