当某个 WaitHandle 正在调用 WaitOne 时,如何关闭应用程序?
当某些 WaitHandle
对象可能处于对 WaitOne
的当前阻塞调用状态时,是否有一种标准方法可以“干净地”关闭应用程序?
例如,可能有一个后台线程在这样的方法中旋转:
while (_request.WaitOne())
{
try
{
_workItem.Invoke();
}
finally
{
OnWorkCompleted();
}
}
我认为没有明显的方法可以在不调用 Thread.Abort 的情况下处理该线程(据我所知,不鼓励这样做) 。但是,对 _request
对象(AutoResetEvent
)调用 Close
将会引发异常。
目前,运行此循环的线程的 IsBackground
属性设置为 true
,因此应用程序似乎能够正确关闭。但是,由于 WaitHandle
实现了 IDisposable
,我不确定这是否被认为是合理的,或者该对象是否真的应该在应用程序退出之前被处置。
这是一个糟糕的设计吗?如果不是,通常如何处理这种情况?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
定义一个名为
_terminate
的附加WaitHandle
,它将发出终止循环的请求,然后使用WaitHandle.WaitAny
而不是WaitHandle.WaitOne
。Define an additional
WaitHandle
called_terminate
that will signal a request to terminate the loop and then useWaitHandle.WaitAny
instead ofWaitHandle.WaitOne
.当一个线程阻塞时(无论它阻塞在什么地方),你可以调用 Thread.Interrupt() ,这将导致异常 ThreadInterruptedException (我相信,这可能有点不同)您可以在线程本身上处理此异常并进行任何必要的清理。
值得注意的是,线程只有在阻塞时才会抛出 ThreadInterruptedException ,如果没有阻塞,直到下次尝试阻塞时才会抛出 ThreadInterruptedException 。
这是我所读到的有关该主题的内容中结束线程的“安全”方式。
另外值得注意的是:如果对象同时实现了 IDisposable 和终结器(如果它使用非托管资源,则会实现),GC 将调用通常调用 dispose 的终结器。通常这是不确定的。然而你几乎可以保证他们会在应用程序退出时被调用。只有在非常特殊的情况下他们才不会。 (抛出 .net 环境终止异常,例如
StackOverflowException
)When a thread is blocking (regardless of what it's blocking on) you can call
Thread.Interrupt()
This will cause the exceptionThreadInterruptedException
(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)将
IsBackground
属性设置为true
...它应该在您的应用结束时自动关闭线程。或者,您可以通过调用
来中断线程Thread.Interrupt
并处理ThreadInterruptedException
。另一个想法是调用 _request.Set() 并使 while 循环检查易失性标志以确定应用程序是否正在关闭或是否应该继续:Set the
IsBackground
property totrue
... it should automatically close the thread when your app ends.Alternately, you can interrupt the thread by calling
Thread.Interrupt
and handle theThreadInterruptedException
. 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:我认为操作系统会在进程完成后进行清理。因为您的线程被标记为 IsBackground,所以 CLR 将结束进程及其中的所有线程,因此这不是问题。
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.