Win32在进程崩溃时未发布命名的互斥锁

时间:2013-02-20 16:43:16

标签: winapi win32-process

我有2个进程(A,B)共享相同的互斥锁(使用WaitForSingleObject / ReleaseMutex调用)。一切正常,但当进程A崩溃时,进程B正在快乐地哼唱。当我重新启动进程A时,就会出现死锁。

更深入的调查显示,在进程A崩溃后,进程B可以成功调用ReleaseMutex()两次。

我的解释:在进程A崩溃后,互斥锁仍然被锁定,但是互斥锁的所有权很容易转移到进程B(这是一个错误)。这就是为什么它快乐地哼着,调用WaitForSingleObject(得到WAIT_OBJECT_0)和ReleaseMutex(得到TRUE作为回报)。

是否可以使用类似于Mutex的命名同步原语,以便进程A中的崩溃将释放互斥锁?

一个解决方案是使用SEH并捕获崩溃并释放互斥锁,但我真的希望Windows有一个健壮的原语,它不会像进程崩溃那样死锁。

2 个答案:

答案 0 :(得分:25)

您必须在此处做一些关于互斥锁如何在Windows上运行的基本假设:

  • 互斥锁是一个被引用计数的操作系统对象。它将不会消失,直到互斥锁上的最后一个句柄关闭
  • 操作系统关闭进程终止时未关闭的任何句柄,减少引用计数
  • 互斥是重入,在同一个线程上的互斥锁上调用WaitForSingleObject成功,需要使用相同数量的ReleaseMutex调用进行平衡
  • 当拥有它的线程终止而不调用ReleaseMutex时,拥有的互斥锁变为放弃。在此状态下在互斥锁上调用WaitForSingleObject会生成WAIT_ABANDONED错误返回码
  • 它绝不是操作系统中的错误。

所以你可以通过观察到的结论得出结论。当A崩溃时,互斥锁没有任何反应,B仍然有一个手柄。唯一可能的方式B可以注意到A崩溃是在A崩溃时它拥有互斥锁。由于B将陷入僵局,因此非常低的几率并且很容易观察到。更有可能的是B会很高兴地开始运转,因为它现在完全没有阻挡,没有其他人会再获得互斥锁了。

此外,A启动时的死锁证明了您已经知道的事情:B由于某种原因永久拥有互斥锁。可能是因为它以递归方式获得了互斥锁。你知道这个,因为你注意到你必须两次调用ReleaseMutex。这是您需要修复的错误。

您需要保护自己免受崩溃的兄弟进程的影响,并且需要为此编写显式代码。在兄弟上调用OpenProcess以获取进程对象的句柄。当进程终止时,句柄上的WaitForSingleObject调用将完成。

答案 1 :(得分:9)

如果持有互斥锁的进程崩溃,那么它就会被抛弃。它取决于其他应用程序如何处理从等待函数返回的状态。

如果它返回WAIT_ABANDONED那么它可以继续进行,好像一切正​​常(可能是它现在做的那样)或“可能不稳定的数据,谨慎行事”。 所有权不会自动传递给其他流程。