C++14并发编程问题:消费者线程需等生产者完成才同步
解决Condition Variable导致消费者等待生产者全部完成才同步的问题
嘿,我懂你碰到的这个问题——刚用condition_variable写生产者消费者模型时,很容易踩这个坑:本来想做到生产一个就消费一个,结果变成了生产者把所有数据都塞完,消费者才开始干活,对吧?
问题根源分析
你的代码大概率是这两个原因导致的:
- 生产者只在所有元素都添加完后才调用一次
notify_one()/notify_all(),而不是每生产一个就通知一次; - 消费者的等待逻辑只检查了
done标志,没同时检查共享容器里有没有新元素,导致它一直阻塞到生产者标记完成才被唤醒。
修正后的完整代码
下面是调整后的生产者/消费者示例,能实现生产一个就消费一个的同步逻辑:
#include <iostream> #include <thread> #include <condition_variable> #include <vector> #include <atomic> #include <mutex> #include <chrono> std::atomic<bool> done{false}; std::mutex data_mutex; // 用来保护共享vector的互斥量 std::condition_variable data_ready; std::vector<int> shared_data; // 生产者线程:逐个生产数字并通知消费者 void producer() { for (int i = 0; i < 10; ++i) { { // 锁范围内操作共享容器,保证线程安全 std::lock_guard<std::mutex> lock(data_mutex); shared_data.push_back(i); } // 解锁后立即通知消费者有新数据 data_ready.notify_one(); // 模拟生产耗时,方便看同步效果 std::this_thread::sleep_for(std::chrono::milliseconds(100)); } // 标记生产完成,最后再通知一次避免消费者阻塞 done = true; data_ready.notify_one(); } // 消费者线程:等待新数据并及时处理 void consumer() { while (true) { std::unique_lock<std::mutex> lock(data_mutex); // 用带谓词的wait避免虚假唤醒,等待条件是「有新数据」或「生产者已完成」 data_ready.wait(lock, []{ return !shared_data.empty() || done.load(); }); // 一次性处理所有可用数据(避免多次唤醒) while (!shared_data.empty()) { std::cout << "消费了数字: " << shared_data.front() << std::endl; shared_data.erase(shared_data.begin()); } // 生产者完成且没有剩余数据时,退出线程 if (done.load() && shared_data.empty()) { break; } } std::cout << "消费者线程已退出" << std::endl; } int main() { std::thread prod_thread(producer); std::thread cons_thread(consumer); prod_thread.join(); cons_thread.join(); return 0; }
关键调整点说明
- 保护共享数据:
shared_data必须被data_mutex包裹,因为vector的读写操作不是线程安全的,任何对它的操作都要在锁的范围内进行; - 及时通知:生产者每添加一个元素就调用
notify_one(),这样消费者能立刻被唤醒处理新数据,而不是等全部生产完毕; - 正确的等待条件:使用
wait()的重载版本,传入lambda谓词,既可以避免虚假唤醒,又明确了消费者需要等待的触发条件; - 收尾通知:生产者完成后必须再调用一次
notify_one(),否则消费者可能会一直阻塞在wait()上——因为此时done已经为true,但它没机会检查这个条件。
这样调整后,你就能看到消费者跟着生产者的节奏,生产一个就消费一个啦~
内容的提问来源于stack exchange,提问作者Andres Barrio
相关产品推荐
相关产品推荐

