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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 11:57:03