C++中用condition_variable实现多生产者消费者遇阻塞问题求助
生产者消费者模型阻塞问题排查
问题描述
尝试用C++的std::condition_variable实现生产者消费者模型,使用ready(消费者等待标记)和processed(生产者等待标记)两个布尔变量协调线程,但运行后生产者很快出现阻塞。日志显示消费者完成数据处理后,没有成功唤醒生产者继续生产。
生产者与消费者代码
void producer() { bool shouldQuit = false; while (!shouldQuit) { std::unique_lock lk(md); std::cout << "p" << threadid << " waiting" << std::endl; cv.wait(lk, [] { return processed; }); processed = false; std::cout << "p" << threadid << " finished waiting" << std::endl; if (d < 10) { data = "p" + std::to_string(threadid) + " " + std::to_string(d); std::cout << data << std::endl; d++; std::cout << "p" << threadid << " unlocking" << std::endl; ready = true; lk.unlock(); std::cout << "p" << threadid << " unlocked" << std::endl; cv.notify_one(); } else { shouldQuit = true; } } } void consumer() { bool shouldQuit = false; while (!shouldQuit) { std::unique_lock lk(md); std::cout << "c" << threadid << " waiting" << std::endl; cv.wait(lk, [] { return ready; }); ready = false; std::cout << "c" << threadid << " finished waiting" << std::endl; if (data.empty()) { shouldQuit = true; } else { std::cout << "c" << threadid << " < " << data << std::endl; processed = true; } std::cout << "c" << threadid << " unlocking" << std::endl; lk.unlock(); cv.notify_one(); std::cout << "c" << threadid << " unlocked" << std::endl; } }
运行日志
prod 0 p0 waiting p0 finished waiting p0 0 p0 unlocking p0 unlocked p0 waiting prod 1 p1 waiting cons 2 c2 waiting c2 finished waiting c2 < p0 0 c2 unlocking c2 unlocked c2 waiting p0 finished waiting p0 1 p0 unlocking p0 unlocked p0 waiting cons 3 c3 waiting c3 finished waiting c3 < p0 1 c3 unlocking <--- this should unblock any producer to produce more, but it doesn't :( c3 unlocked c3 waiting
问题排查提示
条件变量复用导致唤醒错误线程
当前生产者和消费者共用同一个std::condition_variable实例。调用notify_one()时,系统会从等待该变量的线程中随机唤醒一个——日志场景中,消费者c3的通知可能唤醒了另一个等待的消费者c2,而非生产者。被唤醒的c2检查ready为false后会再次进入等待,导致生产者持续阻塞。
修复:为生产者和消费者分别创建独立的条件变量(如cv_prod和cv_cons),消费者处理完成后调用cv_prod.notify_one()唤醒生产者,生产者生产完成后调用cv_cons.notify_one()唤醒消费者。调整通知时机到互斥锁释放前
建议在保持互斥锁锁定的状态下调用notify,避免信号丢失风险。比如消费者可以在设置processed = true后立即调用cv_prod.notify_one(),再释放锁,确保生产者被唤醒时能看到正确的状态。严格保证共享变量的线程安全
所有共享变量(processed、ready、data、d)的读写操作必须在互斥锁保护范围内,避免数据竞争导致的状态混乱。当前代码中这部分操作符合规范,需继续保持。
内容的提问来源于stack exchange,提问作者Andrei Gheorghe
相关产品推荐
相关产品推荐

