views:

70

answers:

4

Is there a standard way to close out an application "cleanly" while some WaitHandle objects may be in the state of a current blocking call to WaitOne?

For example, there may be a background thread that is spinning along in a method like this:

while (_request.WaitOne())
{
    try
    {
        _workItem.Invoke();
    }
    finally
    {
        OnWorkCompleted();
    }
}

I see no obvious way to dispose of this thread without calling Thread.Abort (which from what I understand is discouraged). Calling Close on the _request object (an AutoResetEvent), however, will throw an exception.

Currently, the thread that is running this loop has its IsBackground property set to true, and so the application appears to close properly. However, since WaitHandle implements IDisposable, I'm unsure if this is considered kosher or if that object really ought to be disposed before the app exits.

Is this a bad design? If not, how is this scenario typically dealt with?

+1  A: 

Set the IsBackground property to true... it should automatically close the thread when your app ends.

Alternately, you can interrupt the thread by calling Thread.Interrupt and handle the ThreadInterruptedException. Another idea is to call _request.Set() and make the while loop check a volatile flag to determine if the application is closing or if it should continue:

private volatile bool _running = true;
while(_request.WaitOne() && _running)
{
    //...
}

// somewhere else in the app
_running = false;
_request.Set();
Lirik
So you're saying there's no need to call `Close` on the `WaitHandle` as long as the thread is a background thread?
Dan Tao
@Dan, it has always exited correctly for me... I'm looking for something in the documentation to back that claim up.
Lirik
This is the exact same thing as Thread.Abort(). It is just that the CLR will call it.
Hans Passant
+1  A: 

When a thread is blocking (regardless of what it's blocking on) you can call Thread.Interrupt() This will cause the exception ThreadInterruptedException (I believe, it might be a little different) You can handle this exception on the thread itself and do any neccesary clean up.

It's worth noting, that the thread will only throw the ThreadInterruptedException when it is blocking, if it's not blocking it won't be thrown until it next tries to block.

This is the "safe" way of ending threads from what I've read on the subject.

also worth noting: If the object implements both IDisposable and a finializer (which it will if it uses unmanaged resources) the GC will call the finalizer which normally calls dispose. Normally this is non-deterministic. However you can pretty much guarantee they will get called on application exit. Only under very special circumstances they wouldn't. (A .net environment termininating exception such as StackOverflowException is thrown)

Sekhat
A: 

I think the operating system will clean up after your process has finished. Because your thread is marked as IsBackground the CLR will end the process and all the threads within, so this is not a problem.

Grzenio
+2  A: 

Define an additional WaitHandle called _terminate that will signal a request to terminate the loop and then use WaitHandle.WaitAny instead of WaitHandle.WaitOne.

var handles = { _request, _terminate };
while (WaitHandle.WaitAny(handles) == 0)
{
  try
  {
    _workItem.Invoke();
  }
  finally
  {
    OnCompleteWork();
  }
}
Brian Gideon
+1, this is the correct answer. Do not worry about disposing the handles, the program is terminating. The finalizer will run almost immediately anyway.
Hans Passant
I also agree; this is the best answer out of all of these.
Stephen Cleary
Totally makes sense. But does this mean that it's *not* OK to simply have the thread running this loop initialized with `IsBackground = true` (so that when the app exits, the loop terminates even though the `WaitHandle` is still waiting)?
Dan Tao
@Dan: That's probably okay too, but this method would allow you to gracefully end the thread without having to shutdown the entire application.
Brian Gideon