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

关于《C++程序设计语言》中条件变量实现生产者-消费者队列的技术问询

《C++程序设计语言》中条件变量实现生产者-消费者队列的技术问询

嘿,我刚好在Stroustrup的*《C++程序设计语言》*里看到过这个经典的生产者-消费者队列实现,用条件变量来协调线程间的同步,给你拆解一下这段代码的核心逻辑和细节:

首先,先明确几个核心的共享组件:

  • Message类:这是我们要在线程间传递的消息载体,代码里省略了具体实现,你可以根据业务需求添加数据成员和处理方法。
  • queue<Message> mqueue:用来存储消息的缓冲区队列,是生产者和消费者共享的资源。
  • condition_variable mcond:条件变量,是线程间的“通知器”,用来在队列状态变化时(比如从空变为有消息)唤醒等待的线程。
  • mutex mmutex:互斥锁,用来保护对共享队列的所有操作,避免多个线程同时读写导致数据竞争和不一致。

生产者线程代码

生产者的逻辑很简单:持续生成消息,然后安全地把消息放进队列,再通知消费者有新消息了。

class Message {    // 线程间传递的消息对象
      //... 可自定义成员和方法
};

queue<Message> mqueue;           // 消息队列
condition_variable mcond;        // 同步用的条件变量
mutex mmutex;                    // 互斥锁

void producer()
{
     while(true) {
          Message m;
           //... 填充消息内容 ...
          unique_lock<mutex> lck {mmutex};   // 加锁,确保对队列的操作是线程安全的
          mqueue.push(m);
          mcond.notify_one();                // 唤醒一个等待中的消费者线程
     }                                       // 函数结束时,unique_lock自动释放锁
}

这里用unique_lock而不是lock_guard的原因是:条件变量的wait方法需要灵活地解锁和重新加锁,unique_lock支持这种操作,而lock_guard是一次性的加锁解锁,做不到这点。notify_one()只会唤醒一个等待的消费者,如果有多个消费者线程,也可以用notify_all(),不过notify_one()在单消费者场景下更高效。

消费者线程代码

消费者的核心是等待队列中有消息,然后取出并处理:

void consumer()
{
     while(true) {
          unique_lock<mutex> lck{mmutex};              // 先获取互斥锁
          // 等待,直到队列非空;这里的lambda是防止虚假唤醒的关键
          mcond.wait(lck,[this]{ return !mqueue.empty(); });
          
          Message m = mqueue.front();
          mqueue.pop();
          lck.unlock(); // 可以提前解锁,避免处理消息时占用锁,提升并发效率
          
          //... 处理拿到的消息m ...
     }
}

重点说一下mcond.wait()的作用:

  1. 调用wait时,它会自动释放持有的互斥锁,然后让线程进入等待状态,避免占用锁导致生产者无法写入。
  2. 当生产者调用notify_one()后,这个线程会被唤醒,然后重新获取互斥锁。
  3. 唤醒后会立刻检查lambda表达式的条件(队列是否非空)——这一步是为了应对虚假唤醒(线程可能被莫名唤醒,但此时队列还是空的),只有条件满足时才会继续执行,否则会再次进入等待。

额外注意事项

  • 虚假唤醒:千万不能省略lambda条件检查,必须确保队列确实有消息后再进行取消息操作,否则会出现未定义行为。
  • 锁的范围:处理消息的代码不需要持有锁,所以可以提前调用lck.unlock(),让生产者能更快地获取锁写入消息,提升整体的并发性能。
  • 线程安全:所有访问mqueue的操作(包括检查空、push、pop)都必须在持有mmutex的情况下进行,否则会出现数据竞争。

备注:内容来源于stack exchange,提问作者Mathai

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.16 07:14:32