核心原因是wait()前未加锁或唤醒后未重检条件,导致虚假唤醒被忽略;正确做法是用std::unique_lock配合带谓词的wait()自动重检条件。

为什么用 std::mutex 和 std::condition_variable 实现生产者消费者容易卡死?
核心原因是:wait() 调用前没加锁,或唤醒后没重新检查条件,导致虚假唤醒(spurious wakeup)被忽略。比如生产者发了 notify_one(),但消费者在 wait() 前刚把缓冲区读空,醒来直接取数据就崩溃。
正确做法是把条件判断包进 wait() 的 lambda 或谓词里,让系统自动重检:
std::unique_lock<std::mutex> lock(mtx);
cond.wait(lock, [&] { return !buffer.empty(); }); // 醒来后自动再判一次
- 必须用
std::unique_lock(不能用std::lock_guard),因为wait()会临时释放锁 - lambda 返回
false时线程继续等待;返回true才往下走 - 即使没被 notify,也可能被系统唤醒,所以绝不能省略条件检查
缓冲区用 std::queue 还是 std::deque?
两者都行,但 std::queue 是适配器,默认底层是 std::deque,语义更清晰——你确实只需要队列的 FIFO 行为。
注意别直接暴露 std::queue 的引用或指针给多线程操作;所有访问必须串行化:
立即学习“C++免费学习笔记(深入)”;
std::queue<int> buffer; std::mutex mtx; std::condition_variable cond_producer; // 消费者取完通知生产者 std::condition_variable cond_consumer; // 生产者塞满通知消费者
- 不要用
std::vector模拟队列(push_back()+erase(begin())),性能差且非原子 - 如果需要容量限制(比如固定大小环形缓冲),改用
std::array+ 读写索引,但得自己管边界和空满判断 -
std::queue::size()在多线程下不可靠(无锁读可能看到中间态),判断空满一律用empty()/full()自定义逻辑
如何避免生产者“撑爆”缓冲区或消费者“饿死”?
关键不是加更多锁,而是用两个 condition variable 分开控制:一个等“有空间”,一个等“有数据”。否则单个变量会导致竞争或唤醒错位。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
典型错误是只用一个 cond,生产者 notify 后消费者醒了,但缓冲区还是空(比如 notify 发生在加锁前)。
- 生产者逻辑:锁住 → 等
buffer.size() < capacity→ 入队 →cond_consumer.notify_one() - 消费者逻辑:锁住 → 等
!buffer.empty()→ 出队 →cond_producer.notify_one() - notify 放在锁内更安全(尤其多核下),虽然标准允许锁外 notify,但锁内可避免唤醒丢失
- 如果用
notify_all(),要小心惊群——多个消费者同时醒,但只有一个能取到数据,其余又回去等
调试时看到 std::system_error: Operation not permitted 怎么办?
这通常发生在 Linux 下用 std::condition_variable::wait() 时传入的 std::unique_lock 没持有锁,或者锁已被 move 走。
常见触发点:
- 把
std::unique_lock声明在 if 分支里,然后跨作用域传给wait() - 误用
std::move(lock)后又调wait()(lock 已失效) - 用
std::mutex直接构造std::unique_lock但忘了传std::defer_lock
最稳妥写法:
std::unique_lock<std::mutex> lock(mtx); // 构造即加锁
cond.wait(lock, [&]{ return !buffer.empty(); });
如果真要延迟加锁,显式写:std::unique_lock<std::mutex> lock(mtx, std::defer_lock);
实际跑起来卡住比报错更难查——建议加日志打在 wait 前后,确认锁状态和 buffer 大小变化是否符合预期。

















