//-----------------------------------------------------------------------------------
// Used by a producer to signal that it is done producing new elements. This will
// also wake up any consumers that have gone to sleep.
//
internal void SetDone()
{
TraceHelpers.TraceInfo("tid {0}: AsynchronousChannel<T>::SetDone() called",
Environment.CurrentManagedThreadId);
// This is set with a volatile write to ensure that, after the consumer
// sees done, they can re-read the enqueued chunks and see the last one we
// enqueued just above.
_done = true;
// We set the event to ensure consumers that may have waited or are
// considering waiting will notice that the producer is done. This is done
// after setting the done flag to facilitate a Dekker-style check/recheck.
//
// Because we can race with threads trying to Dispose of the event, we must
// acquire a lock around our setting, and double-check that the event isn't null.
//
// Update 8/2/2011: Dispose() should never be called with SetDone() concurrently,
// but in order to reduce churn late in the product cycle, we decided not to
// remove the lock.
lock (this)
{
if (_consumerEvent != null)
{
_consumerEvent.Set(_index);
}
}
}