public async Task WaitAsync(CancellationToken cancellationToken = default(CancellationToken)) { var spinner = new SpinWait(); while (true) { var capturedCounter = Interlocked.CompareExchange(ref counter, 0, 0); var nextCounter = capturedCounter - 1; if (Interlocked.CompareExchange(ref counter, nextCounter, capturedCounter) == capturedCounter) { if (capturedCounter > 0) { return; } else { var latch = new AsyncLatch(); var waitContext = new WaitContext { Latch = latch }; try { waitContexts.Enqueue(waitContext); await latch.WaitAsync(cancellationToken).ConfigureAwait(false); return; } catch (OperationCanceledException e) { if (ResolveWaitContextUndoAsync(waitContext)) { throw; } else { await waitContext.Latch.WaitAsync(CancellationToken.None).ConfigureAwait(false); return; } // return ResolveWaitContextUndoAsync(waitContext, e); } } } spinner.SpinOnce(); } }
public Task WaitAsync(CancellationToken token = default(CancellationToken)) { var spinner = new SpinWait(); while (!token.IsCancellationRequested) { var previousValue = Interlocked.CompareExchange(ref state, kStateNeutral, kStateSet); if (previousValue == kStateSet) { return(Task.FromResult(false)); } var nextValue = previousValue + 1; if (Interlocked.CompareExchange(ref state, nextValue, previousValue) == previousValue) { var latch = new AsyncLatch(); latches.Enqueue(latch); return(latch.WaitAsync(token)); } spinner.SpinOnce(); } token.ThrowIfCancellationRequested(); // impossible code throw new InvalidStateException(); }