【发布时间】:2008-11-21 23:32:45
【问题描述】:
我有一个线程,当它的函数退出其循环(退出由事件触发)时,它会进行一些清理,然后设置一个不同的事件让主线程知道它已经完成。
但是,在某些情况下,SetEvent() 在设置线程的“我完成”事件后似乎不会返回。
此线程是 DLL 的一部分,并且在加载/附加 DLL、启动线程、结束线程以及多次分离/卸载 DLL 且应用程序未在其间关闭的情况下,该问题似乎发生了。在此问题发生之前必须重复此序列的次数是可变的。
如果您怀疑我知道我在说什么,我已经通过将 SetEvent() 调用与对 OutputDebugString() 的调用括起来来确定发生了什么。出现 SetEvent() 之前的输出。然后,等待线程产生指示事件已设置的输出。
但是,退出线程中对 OutputDebugString() 的第二次调用(在 SetEvent() 之后的那个)永远不会发生,或者至少它的字符串永远不会出现。如果发生这种情况,应用程序会在片刻后崩溃。
(请注意,对 OutputDebugString() 的调用是在问题开始发生后添加的,因此它不太可能挂在那里,而不是在 SetEvent() 中。)
我不完全确定导致崩溃的原因,但它发生在 SetEvent() 没有立即返回的同一个线程中(我一直在跟踪/输出线程 ID)。我想 SetEvent() 有可能最终返回,此时它返回的上下文已经消失/无效,但是什么会导致这样的延迟?
原来看这段代码这么久我都被蒙蔽了,甚至都没有想到去检查返回码。我今天已经看完了,所以我会在星期一知道它返回了什么(如果它返回了),然后我会用该信息编辑这个问题。
更新:我将(主)代码更改为等待线程退出而不是设置事件,并从从线程中删除了 SetEvent() 调用。这改变了 bug 的性质:现在,它不再从 SetEvent() 返回,而是根本不退出线程,整个事情都挂起。
这表明问题不在于 SetEvent(),而是更深层次的问题。还不知道是什么,但最好不要追着那条死胡同。
更新(09 年 2 月 13 日):
事实证明,当我问这个问题时,问题比我想象的要深。 jdigital(可能还有其他人)几乎解决了根本问题:我们试图在分离 DLL 的过程中卸载线程。
我当时没有意识到,但后来通过这里和其他地方的研究(例如 Raymond Chen 的博客)发现,这是一件非常糟糕的事情。
问题在于,由于它的编码方式和行为方式,这并不明显是潜在的问题 - 它被伪装成我必须克服的各种其他不良行为。
这里的一些建议帮助我做到了这一点,所以我感谢所有做出贡献的人。谢谢!
【问题讨论】:
标签: windows