C++生产者消费者模型异常排查:为何先填满缓冲区再消费?
问题分析与修复
你的代码核心问题是生产者和消费者在持有互斥锁的状态下执行sleep操作,导致锁被长时间占用,对方线程完全无法获取锁执行任务:
具体原因
- 生产者线程中,
std::this_thread::sleep_for(std::chrono::seconds(1));写在unique_lock<mutex> lk(mtx);的作用域内——也就是持有锁的状态下休眠。这意味着生产者每生产一个数据后,会攥着锁睡1秒,这段时间消费者根本抢不到锁,没机会进入消费逻辑。 - 只有当生产者把缓冲区填满(达到容量n=2),
cv.wait(lk,[&](){return q.size()<n;})的条件不满足,生产者才会释放锁进入等待状态,这时候消费者才能抢到锁开始消费。 - 同理,消费者拿到锁后也带着锁休眠,后续生产者也得等消费者休眠结束才能抢锁,完全失去了多线程并发的意义。
修复方案
把sleep操作移到互斥锁作用域之外,确保锁只在操作共享资源时持有,其余时间释放:
修复后的代码
#include <iostream> #include <mutex> #include <thread> #include <queue> #include <chrono> using namespace std; std::mutex mtx; condition_variable cv; queue<int> q; int n=2; int produceData() { int res=rand()%1000; cout<<"produce data:"<<res<<endl; return res; } void consumeData(int data) { cout<<"consume data:"<<data<<endl; } void producer(){ while(true) { { // 用花括号缩小锁的作用域 unique_lock<mutex> lk(mtx); cv.wait(lk,[&](){return q.size()<n;}); q.push(produceData()); cv.notify_one(); } // 锁在这里自动释放 std::this_thread::sleep_for(std::chrono::seconds(1)); } } void consumer() { while(true) { int data; { unique_lock<mutex> lk(mtx); cv.wait(lk,[&](){return q.size()>0;}); data = q.front(); q.pop(); consumeData(data); cv.notify_one(); } // 锁在这里自动释放 std::this_thread::sleep_for(std::chrono::seconds(1)); } } int main() { std::thread t1(producer); std::thread t2(consumer); t1.join(); t2.join(); return 0; }
额外优化点
- 把
consumeData改成接收参数的形式,避免在消费时直接访问共享队列,减少锁内的操作时间。 - 用花括号明确缩小锁的作用域,确保锁只在操作共享资源时持有,提升并发效率。
内容的提问来源于stack exchange,提问作者Jacob
相关产品推荐
相关产品推荐

