进程崩溃时未释放 Win32 命名互斥锁

Posted

技术标签:

【中文标题】进程崩溃时未释放 Win32 命名互斥锁【英文标题】:Win32 Named mutex not released when process crashes 【发布时间】:2013-02-20 16:43:15 【问题描述】:

我有 2 个进程(A、B)共享同一个互斥锁(使用 WaitForSingleObject / ReleaseMutex 调用)。一切正常,但是当进程 A 崩溃时,进程 B 正在愉快地嗡嗡作响。当我重新启动进程 A 时,出现了死锁。

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

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

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

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

【问题讨论】:

这可能是一篇有趣的文章供您阅读:blogs.msdn.com/b/oldnewthing/archive/2005/09/12/463977.aspx 【参考方案1】:

您必须在这里对互斥锁在 Windows 上的工作方式做出一些基本假设:

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

因此,您可以根据您的观察得出结论。当 A 崩溃时,互斥体没有任何反应,B 仍然有一个句柄。 B 可以注意到 A 崩溃的唯一可能方式是 A 在它拥有互斥锁时崩溃。由于 B 将死锁,因此这种可能性非常低并且很容易观察到。更有可能的是,B 会愉快地继续前进,因为它现在完全畅通无阻,没有其他人会再获得互斥体。

此外,A 重新开始时的僵局证明了您已经知道的事情:B 出于某种原因永久拥有互斥锁。可能是因为它递归地获取了互斥锁。您知道这一点是因为您注意到您必须调用 ReleaseMutex 两次。这是您需要修复的错误。

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

【讨论】:

对不起,我没有将此标记为答案,但是.. 迟到总比永远好。谢谢,我不知道废弃状态的含义。【参考方案2】:

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

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

【讨论】:

我的猜测是进程 B 收到 WAIT_ABANDONED 并认为这意味着 WAIT_FAILED(而不是“以意想不到的方式成功”)所以它尝试第二次获取互斥锁。跨度>

以上是关于进程崩溃时未释放 Win32 命名互斥锁的主要内容,如果未能解决你的问题,请参考以下文章

共享内存锁定和进程崩溃

线程因互斥锁而崩溃

等到另一个进程锁定然后解锁 Win32 互斥锁

在 windows 中使用互斥锁进行进程间同步(win32 或 C++)

线程同步方式之互斥量Mutex

提升进程间互斥锁崩溃而不是等待锁定?