Waiting on Semaphore may still be executing code on the same thread

408 Views Asked by At

Consider the following demo code attached to a button on a Windows Form:

private void button1_Click(object sender, System.EventArgs e)
{
    var semaphore = new SemaphoreSlim(0, 1);

    Invalidate();  // <-- posts a message that surprisingly will be processed while we're waiting
    Paint += onPaint;
    semaphore.Wait(1000);
    Paint -= onPaint;

    void onPaint(object s, PaintEventArgs pe)
    {
        throw new System.NotImplementedException();  // we WILL hit this!
    }
}

Although we are hanging on a semaphore wait on the UI thread, the paint message posted by Invalidate() will still be executed while we're hanging on the Wait() - AND (of course) on the UI thread.

This demonstrates the root cause for a bug which I'm trying to create a failing Unit Test for - without using any Windows Form. I've been playing with custom SyncronizationContexts and TaskSchedulers for a few hours now but I have not been able to make this happen on the same thread.

What I would like to do, in pseudo code, would be something like:

[Test]
public void Test()
{
    // something magic - this doesn't help:
    // SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());

    SynchonizationContext.Current.Post(MethodToBeExecutedWhileWeAreWaitingAndOnThisVeryThread);
    var semaphore = new SemaporeSlim(0, 1);
    AssertThatMethodHasNotBeenCalled();
    semaphore.Wait(1000);
    AssertThatMethodGotCalled();
}
0

There are 0 best solutions below