新闻中心 分类>>

c++如何使用条件变量std::condition_variable 实现生产者消费者模型【并发编程】

2025-12-21 00:00:00
浏览次数:
返回列表
需配合使用std::mutex、std::condition_variable和共享缓冲容器;wait必须用while循环防虚假唤醒;notify_one更高效;cv.wait(lock)原子地释放锁、等待、重加锁。

std::condition_variable 实现生产者消费者模型,核心是让生产者在缓冲区满时等待,消费者在缓冲区空时等待,同时用互斥锁保护共享队列,用条件变量精准唤醒对应线程。

需要哪些同步组件

必须配合使用三样东西:std::mutex(保护共享队列)、std::condition_variable(协调等待与唤醒)、一个共享的缓冲容器(如 std::queue)。不能只用条件变量,它不带状态,也不提供互斥能力。

关键逻辑:wait() 必须搭配 while 循环检查条件

不能写成 if (queue.empty()) cv.wait(lock),因为存在虚假唤醒(spurious wakeup)和条件变化竞争。正确写法是:

  • while (queue.empty()) cv.wait(lock); —— 消费者等非空
  • while (queue.size() >= capacity) cv.wait(lock); —— 生产者等有空位

每次被唤醒后都要重新检查条件是否真正满足,这是安全前提。

notify_one() 还是 notify_all()?

一般用 notify_one() 就够了:

  • 生产者 push 后调用 cv_not_empty.notify_one(),唤醒一个等待消费的线程
  • 消费者 pop 后调用 cv_not_full.notify_one(),唤醒一个等待生产的线程

除非你明确需要唤醒所有线程(比如广播式通知),否notify_one() 更高效、更可控,避免惊群效应。

注意 unlock 和 wait 的原子性

cv.wait(lock) 会自动执行「释放锁 → 等待 → 被唤醒时重新加锁」三个动作,且整个过程是原子的。不要手动 unlock 再 wait,否则会出竞态。例如:

  • ❌ 错误:lock.unlock(); cv.wait(lock);
  • ✅ 正确:cv.wait(lock, [&]{ return !queue.empty(); }); 或分步写为 while(...) cv.wait(lock);

推荐直接用带谓词的 wait 版本,简洁又不易出错。

不复杂但容易忽略。把互斥、等待、唤醒、条件重检这四步串对,模型就稳了。

搜索