8

WaitHandle当某些对象可能处于当前阻塞调用的状态时,是否有一种标准方法可以“干净地”关闭应用程序WaitOne

例如,可能有一个后台线程以这样的方法旋转:

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

我认为没有明显的方法可以在不调用的情况下处理这个线程Thread.Abort(据我所知,这是不鼓励的)。Close但是,调用_request对象 (an AutoResetEvent) 会引发异常。

目前,运行此循环的线程将其IsBackground属性设置为true,因此应用程序似乎正常关闭。但是,由于WaitHandleimplements IDisposable,我不确定这是否被认为是犹太洁食,或者该对象是否真的应该在应用程序退出之前被处置。

这是一个糟糕的设计吗?如果不是,通常如何处理这种情况?

4

4 回答 4

8

定义一个附加WaitHandle调用_terminate,它将发出终止循环的请求,然后使用WaitHandle.WaitAny而不是WaitHandle.WaitOne.

var handles = { _request, _terminate };
while (WaitHandle.WaitAny(handles) == 0)
{
  try
  {
    _workItem.Invoke();
  }
  finally
  {
    OnCompleteWork();
  }
}
于 2010-06-21T19:37:12.017 回答
1

IsBackground属性设置为true... 它应该在您的应用程序结束时自动关闭线程。

或者,您可以通过调用Thread.Interrupt和处理ThreadInterruptedException. 另一个想法是调用_request.Set()并让 while 循环检查一个 volatile 标志以确定应用程序是否正在关闭或是否应该继续:

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

// somewhere else in the app
_running = false;
_request.Set();
于 2010-06-21T19:14:08.790 回答
1

当线程阻塞时(不管它阻塞了什么),您可以调用Thread.Interrupt()这将导致异常ThreadInterruptedException(我相信,它可能会有所不同)您可以在线程本身上处理此异常并进行任何必要的清理。

值得注意的是,线程只会ThreadInterruptedException在它阻塞时抛出,如果它没有阻塞它不会被抛出,直到它下一次尝试阻塞。

这是从我读过的主题中结束线程的“安全”方式。

还值得注意的是:如果对象同时实现了 IDisposable 和终结器(如果它使用非托管资源,它将实现),GC 将调用通常调用 dispose 的终结器。通常这是不确定的。但是,您几乎可以保证它们会在应用程序退出时被调用。只有在非常特殊的情况下他们才不会。(一个 .net 环境终止异常,例如StackOverflowException被抛出)

于 2010-06-21T19:18:27.127 回答
0

我认为操作系统将在您的过程完成后进行清理。因为您的线程被标记为 IsBackground,CLR 将结束进程和其中的所有线程,所以这不是问题。

于 2010-06-21T19:19:03.607 回答