C++14多线程组间互斥组内并发控制实现异常排查
现有实现的核心问题
1. 锁获取逻辑顺序完全颠倒
你在node_a代码中第一步就调用mtx_a.lock_shared()获取同组共享锁,再尝试做组间互斥判断。如果此时grp_b已经持有mtx_a的独占锁(对应node_b逻辑中抢占mtx_a的操作),所有node_a线程会直接阻塞在mtx_a.lock_shared()调用上,后续的组间判断逻辑完全无法执行,甚至会出现两组循环等待的死锁问题。
2. while循环存在无意义空转与竞态
你编写的while(cnt_a==0)循环在mtx_b.try_lock()失败时会持续空转浪费CPU资源,同时:
- 对
cnt_a的无锁读取和mtx_b.try_lock()操作没有原子性保证,极端情况下会出现cnt_a已经被其他线程修改,但当前线程还未感知到的时序问题 - 多个
node_a线程同时争抢mtx_b锁时,会产生不必要的锁竞争开销
3. shared_timed_mutex优先级带来的饥饿问题
std::shared_timed_mutex的锁调度优先级由标准库实现决定,多数实现会优先调度独占锁请求。当grp_a最后一个持有mtx_b独占锁的线程尝试获取mtx_a独占锁时,后续新进入的node_a线程的共享锁请求会被一直阻塞,严重时会出现整组饿死的情况。
4. 计数器操作逻辑冗余
你已经用std::mutex保护cnt_a/cnt_b的修改,完全不需要额外将计数器声明为atomic_int,多余的原子声明反而会带来不必要的内存屏障开销。
极简修复方案
你的需求本质是两组线程同组并发、组间互斥,不需要用两个shared_timed_mutex做复杂控制,用互斥量+条件变量+计数器的组合就能实现,逻辑清晰且没有竞态:
#include <mutex> #include <condition_variable> std::mutex mtx; std::condition_variable cv; int cnt_a = 0, cnt_b = 0; // node_a 实现 void node_a_work() { // 进入组前判断 std::unique_lock<std::mutex> lck(mtx); cv.wait(lck, [&](){ return cnt_b == 0; }); // 等待grp_b全部退出 cnt_a++; lck.unlock(); // 访问共享资源,同组可并发 /* do your work here */ // 退出组 lck.lock(); cnt_a--; if (cnt_a == 0) { cv.notify_all(); // 通知等待的grp_b线程可以进入 } lck.unlock(); } // node_b 实现和node_a逻辑对称,只需要把cnt_a和cnt_b互换即可 void node_b_work() { std::unique_lock<std::mutex> lck(mtx); cv.wait(lck, [&](){ return cnt_a == 0; }); cnt_b++; lck.unlock(); /* do your work here */ lck.lock(); cnt_b--; if (cnt_b == 0) { cv.notify_all(); } lck.unlock(); }
该方案的逻辑保证:
- 只要有
grp_a线程在运行,cnt_a就大于0,所有grp_b线程会阻塞在条件变量等待上,实现组间互斥 - 同一组的线程只要满足进入条件就可以累加计数器后并行执行,实现同组并发
- 没有多余的锁竞争和空转开销,不会出现死锁问题
内容的提问来源于stack exchange,提问作者shangping
相关产品推荐
相关产品推荐

