Windows:什么情况下SetEvent()不能立即返回?

我有一个线程,当它的函数退出其循环(退出是由一个事件触发的),它会做一些清理,然后设置一个不同的事件,让主线程知道它已经完成。

但是,在某些情况下,SetEvent()在设置线程的“我完成”事件后似乎不会返回。

这个线程是一个DLL的一部分,问题似乎发生在DLL加载/附加,线程启动,线程结束和DLL分离/卸载多次,没有closures应用程序之间的应用程序。 在这个问题发生之前,这个序列必须被重复的次数是可变的。

如果你怀疑我在说什么,我已经通过调用OutputDebugString()来调用SetEvent()调用来确定发生了什么。 出现SetEvent()之前的输出。 然后,等待线程产生表示事件已被设置的输出。

但是,在退出线程(一个AFTER SetEvent())中第二次调用OutputDebugString()永远不会出现,或者至less不会出现它的string。 如果发生这种情况,应用程序会在一会儿之后崩溃。

(请注意,调用OutputDebugString()是在问题开始之后添加的,因此不太可能挂在那里,而不是在SetEvent()中。)

我不完全确定是什么导致了崩溃,但它发生在SetEvent()没有立即返回的同一个线程中(我一直在跟踪/输出线程ID)。 我想有可能是SetEvent()最终返回,那么它返回的上下文是否消失/无效,但是什么会导致这样的延迟?

事实certificate,我已经盲目地看着这个代码这么久了,我甚至没有想到要检查返回代码。 我已经完成了今天的工作,所以我会在星期一知道它将返回什么( 如果它正在返回),那么我将用这个信息编辑这个问题。

更新:我更改(主)代码,以等待线程退出,而不是它设置事件,并从从线程删除SetEvent()调用。 这改变了错误的性质:现在,不是无法从SetEvent()返回,而是根本不退出线程,整个事件都是挂起的。

这表明问题不在SetEvent()中,而是深入一些。 不知道是什么,但是不要追逐那个盲人的小巷是件好事。

更新(2009年2月13日):
事实certificate,当我问这个问题时,问题比我想象的要深刻。 jdigital(可能还有其他人)已经明白了底层的问题:我们试图卸载一个线程作为分离DLL的过程的一部分。

这个,就像我当时没有意识到的,但是通过这里和别处的研究发现(例如Raymond Chen的博客)是一件非常糟糕的事情。

问题在于,由于它被编码的方式和行为方式,这并不是显而易见的,这是潜在的问题 – 它被伪装成我必须涉及的各种其他不良行为。

这里的一些build议帮助我做到了这一点,所以我感谢所有贡献的人。 谢谢!

谁在卸载DLL,什么时候卸载完成? 我想知道是否有一个时间问题,这里的DLL是在线程运行完成之前卸载的。

你是不是把一个HANDLE *传给SetEvent ? 事件句柄引用更可能是无效的,崩溃是访问冲突(即访问垃圾)。

您可能想使用WinDbg来捕捉崩溃并检查堆栈。

为什么你需要在slave线程中设置一个事件来触发线程完成? 只是退出线程,调用主线程应该等待工作线程退出,例如伪代码 –

 Master { TerminateEvent = CreateEvent ( ... ) ; ThreadHandle = BeginThread ( Slave, (LPVOID) TerminateEvent ) ; ... Do some work ... SetEvent ( TerminateEvent ) ; WaitForSingleObject ( ThreadHandle, SOME_TIME_OUT ) ; CloseHandle ( TerminateEvent ) ; CloseHandle ( ThreadHandle ) ; } Slave ( LPVOID ThreadParam ) { TerminateEvent = (HANDLE) ThreadParam ; while ( WaitForSingleObject ( TerminateEvent, SOME__SHORT_TIME_OUT ) == WAIT_TIMEOUT ) { ... Do some work ... } } 

有很多的错误条件和状态来检查,但这是我通常如何做的本质。

如果你能掌握它,那么得到这本书,它在很多年前我第一次读到它的时候就改变了我的生活。

高级Windows:Windows NT 3.5和Windows 95的Win32 Api开发指南(平装本)作者Jeffrey Richter(作者)