Search code examples
c#.netsynchronizationcancellationmanualresetevent

Is Wait()-ing on a ManualResetEventSlim guaranteed to throw on cancellation?


Given the following code:

CancellationTokenSource cts = new CancellationTokenSource();
ManualResetEventSlim mre = new ManualResetEventSlim();

and these two threads executing concurrently:

mre.Wait(cts.Token);

cts.Cancel();
mre.Set();

is the first one (call to mre.Wait(cts.Token)) guaranteed to throw an OperationCanceledException or is it also possible that it will just return?

My gut says I should expect either to happen (internal race condition). MSDN does not give an answer, it just says "while observing the CancellationToken".

I'm hoping for an answer with specific details as to how and why.

I would like to pre-empt comments like "you should expect Cancel() and Set() to occur concurrently / in any order, and thus both cases, anyway". I'm fully aware of that.


Solution

  • There is race condition because Wait is implemented like that:

    public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
    {
        ThrowIfDisposed();
        cancellationToken.ThrowIfCancellationRequested(); // an early convenience check
    
        if (millisecondsTimeout < -1)
        {
            throw new ArgumentOutOfRangeException("millisecondsTimeout");
        }
    
        if (!IsSet)
        {
        // lots of stuff here, not relevant
        }
        return true;
    }
    

    Second thread (which both cancels and sets the token) might interrupt first thread right between cancellationToken.ThrowIfCancellationRequested() check and IsSet check.