当某个 WaitHandle 正在调用 WaitOne 时,如何关闭应用程序?

发布于 2024-09-06 04:00:34 字数 665 浏览 3 评论 0原文

当某些 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

瀞厅☆埖开 2024-09-13 04:00:34

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

var handles = { _request, _terminate };
while (WaitHandle.WaitAny(handles) == 0)
{
  try
  {
    _workItem.Invoke();
  }
  finally
  {
    OnCompleteWork();
  }
}

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();
  }
}
甜点 2024-09-13 04:00:34

当一个线程阻塞时(无论它阻塞在什么地方),你可以调用 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 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)

相思故 2024-09-13 04:00:34

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

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

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

// somewhere else in the app
_running = false;
_request.Set();

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();
无语# 2024-09-13 04:00:34

我认为操作系统会在进程完成后进行清理。因为您的线程被标记为 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文