由于AutoResetEvent信号处于WaitOne状态,线程在应用程序终止后仍然存在

本文关键字:终止 应用程序 存在 线程 信号 AutoResetEvent 状态 WaitOne 由于 | 更新日期: 2023-09-27 18:01:31

我有一个应用程序,在队列中使用AutoResetEvent (WaitOne/Set)来处理消息。我注意到,当我从Visual Studio (Shift+F5)终止调试会话时,应用程序的原始进程挂起(但并非总是如此)。我手动重新连接调试器到进程,并看到它有一个线程卡在waitthhandle . waitone上。

所以我的问题是,终止可能处于WaitOne状态的线程的正确方法是什么?

我想到的第一个答案是监听应用程序退出事件并在那里执行Set操作,但我不确定在这些调试会话之后是否可靠地调用了该事件,或者是否存在我不知道的更标准的实践。

并且,作为第二个问题,对于在"生产"模式下运行的应用程序,您会以不同的方式处理这个问题吗?

由于AutoResetEvent信号处于WaitOne状态,线程在应用程序终止后仍然存在

有一个简单的方法可以做到这一点(不是变通)

首先,你需要设置一个事件,当你的应用程序将要结束时触发

// somewhere with global scope. On a singleton or in program class maybe
// this is set when you want to terminate your application
private static ManualResetEvent ExitWaitHandle = new ManualResetEvent(false);

这是如何在其他地方使用

// the event you want to check but it's blocking your application termination
private static AutoResetEvent yourEvent = new AutoResetEvent(true);
// the method where you have the problem
private static void FooAsync()
{
    try
    {
        WaitHandle.WaitAny(new WaitHandle[]{yourEvent, ExitWaitHandle});
        Checkpoint();
        // other stuff here
        // check if thread must die
        Checkpoint();
    }
    catch(ApplicationTerminatingException)
    {
        // thread must die, do cleanup and finalization stuff here
    }
    catch(Exception)
    {
        // holy cow! what should we do?
    }
}
private void CheckPoint()
{
    // fast check if the exit handle is set
    if(ExitWaitHandle.WaitOne(0))
    {
        throw new ApplicationTerminatingException(); // custom exception
    }
}

唯一的开销是,在"一些"代码之后,您需要设置检查点以中止线程。

一种解决方案是使用Thread.IsBackground属性将线程设置为背景线程。当在线程上设置时,该线程不会因为退出而停止进程。

然而,线程可能在任何时候被中断,这通常会导致未定义的行为,这取决于你的线程正在做什么。在我看来,终止线程的最好方法是发出线程退出的信号,例如通过设置退出标志并设置WaitHandle并唤醒它,然后Join使线程退出。