/// <summary> /// Wait on a given position. This will block, until this object has /// <see cref="Increment"/> called up to the position indicated. This /// accepts cancellation tokens, but the default cancellation token also /// works. /// </summary> public void Wait(long position, CancellationToken token = default(CancellationToken)) { if (_ex != null) { throw Contracts.Except(_ex, "Event we were waiting on was subject to an exception"); } if (position <= _currCleared) { return; } WaitStats ev; lock (_waiters) { // No need to do anything in this strange case. if (_ex != null) { throw Contracts.Except(_ex, "Event we were waiting on was subject to an exception"); } if (position <= _currCleared) { return; } ev = new WaitStats(position); _waiters.Add(ev); } ev.Event.Wait(token); if (_ex != null) { throw Contracts.Except(_ex, "Event we were waiting on was subject to an exception"); } }
/// <summary> /// Indicates to the waiter that we want to, at some future point, wait at a given /// position. This object will return a reset event that can be waited on, at the /// point when we actually want to wait. This method itself has the potential to /// signal other events, if by registering ourselves the waiter becomes aware of /// the maximum number of waiters, allowing that waiter to enter its critical state. /// /// If multiple events are associated with the minimum value, then only one will /// be signaled, and the rest will remain unsignaled. Which is chosen is undefined. /// </summary> public ManualResetEventSlim Register(long position) { WaitStats ev; lock (_waiters) { Contracts.Check(_maxWaiters > 0, "All waiters have been retired, Wait should not be called at this point"); // We should never reach the state Contracts.Assert(_waiters.Count < _maxWaiters); ev = new WaitStats(position); // REVIEW: Optimize the case where this is the minimum? _waiters.Add(ev); SignalIfNeeded(); Contracts.Assert(_waiters.Count < _maxWaiters); } // REVIEW: At first I instead returned an action, ev.Event.Wait. // It may be less efficient, but I don't know if returning an action here // is really that bad? return(ev.Event); }