2011-07-08 126 views
3

我有一个应用程序在队列中使用AutoResetEvent(WaitOne/Set)来处理消息。我注意到,当我终止Visual Studio的一个调试会话(Shift + F5)时,应用程序的原始进程挂起(但并非总是)。我手动将调试器重新连接到进程,并发现它在WaitHandle.WaitOne上存在单线程。由于WaitOne状态下的AutoResetEvent信号导致应用程序终止后,线程仍然存在

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

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

而且,作为第二个问题,您是否会以“生产”模式运行的应用程序处理这个问题?

+0

嗯,你手上有一个讨厌的问题。终止调试会话是使用Windows中最大的枪TerminateProcess()完成的。 Taskmgr.exe中使用的同类枪。只有一种可能的方式是,这不会终止进程,内核线程繁忙并且不能完成I/O请求。这绝对不是一个AutoResetEvent。没有意义。 –

+0

@Hans - 一旦连接调试器,我在调用堆栈中看到的WaitHandle不是信号的等待句柄,而是内核I/O任务的不同等待句柄?在这项任务中唯一的I/O是一些日志记录,这真的很简单(只是每隔一段时间手动触发一次,而不是以任何频率发生) – Matt

+0

我所知道的是,你所描述的并不会使感。因此,如果没有任何文档,我会立即假定描述是错误的。发布堆栈跟踪与非托管调试和Microsoft符号服务器启用。 –

回答

4

有一个简单的方法来做到这一点(不是一个解决方法)

首先,您需要设置将火的时候,您的应用程序会死

// 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 
    } 
} 

唯一的开销是,“一些”代码后,你需要设置一个检查点,以中止你的线程。希望这是你正在寻找的。

+1

这是一个非常有趣的答案。我明天会尝试这个第一件事,并让你知道它是如何发生的。谢谢。 – Matt

+0

我现在又看到了这一点,我的代码在我面前,并有几个问题。 1)我认为你的'全局'范围ExitWaitHandle应该公开吗? 2)这里的基本思想是在关机过程中通过ExitWaitHandle打开信号的“门”,从而释放任何等待句柄并允许它们自行处理? – Matt

+0

@Matt是的,你打开“门”!至于事件,它不应该是公开的,而是可以从所有需要监听应用程序终止事件的类访问。您可以实现观察者模式,其中用户是线程。只是一点点代码纳粹评论:我喜欢'内部'关键字而不是'公共'这样的东西。 – Odys

1

一种解决方法是使用Thread.IsBackground属性将线程设置为后台线程。在线程上设置时,线程不会停止退出进程。

但是,线程可能随时中断,通常会导致未定义的行为,具体取决于您的线程正在做什么。以我愚蠢的观点终止线索的最好方法是指示线程退出,例如,通过设置退出标志并设置WaitHandle并将其唤醒然后Join进入线程。

+0

线程实际上是通过.NET 4 Task对象处理的。我想我可以做一些手动线程... – Matt

相关问题