How do you close an application when some WaitHandle is in the middle of a call to WaitOne?
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?
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();
}
}
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)
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();
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.
精彩评论