为何C++ semaphore实现中同一mutex可被多线程多次锁定?
问题解析:为何多个线程都能“获取到同一个Mutex”
你的困惑源于对std::condition_variable::wait行为的误解——当线程调用wait时,它会自动释放持有的Mutex,被唤醒后又会重新获取Mutex。日志里的打印只是记录了线程曾经成功获取过Mutex的时刻,并非同一时刻多个线程持有Mutex。
具体流程拆解
以你的日志为例,逐个关键节点分析:
- 线程0调用
acquire,成功锁定Mutex,打印0 aquired mutex in aquire,此时count_从2减到1,函数执行完毕,unique_lock析构,自动释放Mutex。 - 线程4获取到释放的Mutex,打印
4 aquired mutex in aquire,count_从1减到0,函数执行完毕,释放Mutex。 - 线程3获取Mutex,打印
3 aquired mutex in aquire,发现count_为0,进入cv_.wait(lck):- 这里wait会立即释放Mutex,让其他线程可以竞争获取。
- 线程2此时竞争到Mutex,打印
2 aquired mutex in aquire,同样发现count_为0,调用wait释放Mutex。 - 后续线程5、1重复上述步骤:获取Mutex→打印日志→发现count为0→wait释放Mutex。
这些线程的“获取Mutex”操作是交替进行的,同一时刻永远只有一个线程持有Mutex,日志只是按时间顺序记录了每个线程成功获取Mutex的瞬间,并非同时持有。
额外代码优化建议
- 调整
release函数的执行顺序:当前代码先lck.unlock()再cv_.notify_one(),虽然功能正常,但更稳妥的做法是去掉手动unlock,让unique_lock在函数结束时自动释放Mutex,同时把cv_.notify_one()放在unlock之前(即利用unique_lock的作用域自动管理锁),避免因唤醒时机导致的潜在唤醒丢失。 - 修复随机数生成问题:每个线程调用
srand(id)会重置随机数种子,可能导致多个线程生成相同的等待时间,建议在main函数开头只调用一次srand(time(nullptr))。
内容的提问来源于stack exchange,提问作者Daniel Dobiński
相关产品推荐
相关产品推荐

