You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

线程多次获取Mutex仅释放一次,为何其他线程仍能成功获取?

关于Windows Mutex重复获取后释放异常的疑问

线程函数示例如下:

unsigned WINAPI thread(void *arg)
{
    WaitForSingleObject(hMutex, INFINITE);  
    WaitForSingleObject(hMutex, INFINITE);//wait for mutex twice
    ReleaseMutex(hMutex);
    return 0;
}

MSDN及《Windows via C/C++》指出:“线程每次通过等待函数获取Mutex后,必须调用一次ReleaseMutex。”

当测试线程两次获取Mutex却仅释放一次时,发现其他线程仍能成功获取该Mutex(本应释放异常),请问这是为何?


核心原因:Mutex的递归所有权特性

Windows Mutex是**递归(可重入)**的同步对象,核心规则如下:

  • 同一个线程可以多次调用WaitForSingleObject获取同一个Mutex,每次获取都会增加Mutex的引用计数
  • 每次调用ReleaseMutex会将引用计数减1,只有当引用计数降至0时,Mutex才会真正释放,允许其他线程获取

在你的代码场景中:

  1. 第一次WaitForSingleObject:Mutex引用计数变为1,线程获得所有权
  2. 第二次WaitForSingleObject:因是同一线程,引用计数变为2,线程不会阻塞
  3. 单次ReleaseMutex:引用计数减为1,Mutex仍被当前线程持有,并未真正释放

你观察到其他线程能获取Mutex,大概率是因为线程执行完ReleaseMutex后直接退出:当持有Mutex的线程终止时,Windows会自动释放该线程持有的所有Mutex——无论当前引用计数是多少,系统会强制将计数清零,让其他线程可以获取。

验证测试

修改代码让线程在释放一次后不立即退出,就能看到预期的阻塞行为:

unsigned WINAPI thread(void *arg)
{
    WaitForSingleObject(hMutex, INFINITE);  
    WaitForSingleObject(hMutex, INFINITE);//wait for mutex twice
    ReleaseMutex(hMutex);
    Sleep(5000); // 线程继续存活5秒
    return 0;
}

此时其他线程调用WaitForSingleObject(hMutex, INFINITE)会被阻塞5秒,直到当前线程退出后Mutex被系统自动释放,才能获取到锁。

关键注意事项

  • 即使系统会在线程终止时自动释放Mutex,也必须严格遵循“每次获取对应一次释放”的规则,否则在长期运行的线程场景中会导致逻辑混乱、死锁等问题。
  • 若不需要递归特性,可改用临界区(Critical Section)(默认非递归,可通过InitializeCriticalSectionAndSpinCount配置为递归),或其他非递归同步对象。

内容的提问来源于stack exchange,提问作者Zyber404

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 22:32:17