Search code examples
c#.net-4.0waithandleautoresetevent

Thread persists after application termination due to AutoResetEvent signal in WaitOne state


I have an application that uses an AutoResetEvent (WaitOne/Set) in a queue for processing messages. I'm noticing that when I terminate the a debug session from Visual Studio (Shift+F5) the original process for the application hangs around (but not always). I manually re-attach the debugger to the process, and see it has single thread stuck on WaitHandle.WaitOne.

So my question is, what is the correct way to terminate threads that may be in a WaitOne state?

The first answer that sprang to mind was listen to the Application Exit event and doing a Set there, but I wasn't sure if this event was called reliably after these debug sessions, or if there is a more standard practice that I am not aware of.

And, as a second question, would you handle this differently for the application running in 'production' mode?


Solution

  • There is a simple way to do this (not a workaround)

    First, you need to set an event that will fire when your application is going to die

    // somewhere with global scope. On a singleton or in program class maybe
    // this is set when you want to terminate your application
    private static ManualResetEvent ExitWaitHandle = new ManualResetEvent(false);
    

    And this is how to use it elsewhere

    // the event you want to check but it's blocking your application termination
    private static AutoResetEvent yourEvent = new AutoResetEvent(true);
    
    // the method where you have the problem
    private static void FooAsync()
    {
        try
        {
            WaitHandle.WaitAny(new WaitHandle[]{yourEvent, ExitWaitHandle});
            Checkpoint();
    
            // other stuff here
    
            // check if thread must die
            Checkpoint();
        }
        catch(ApplicationTerminatingException)
        {
            // thread must die, do cleanup and finalization stuff here
        }
        catch(Exception)
        {
            // holy cow! what should we do?
        }
    }
    
    private void CheckPoint()
    {
        // fast check if the exit handle is set
        if(ExitWaitHandle.WaitOne(0))
        {
            throw new ApplicationTerminatingException(); // custom exception
        }
    }
    

    The only overhead is that after "some" code you need to set a checkpoint in order to abort your thread. Hope this is what you were looking for.