C++ 基于mutex与condition_variable的生产者消费者死锁问题求助
死锁根因
当前代码死锁的核心原因是所有餐品生产、消费完成后,剩余消费者线程会永久阻塞:
- 生产者生产完
numero_pratos份餐品后直接退出,不会再发送任何通知 - 仍在等待缓冲区有新餐品的消费者永远等不到唤醒信号,陷入永久等待
另外还有两个隐藏问题:
- 生产、消费的耗时sleep操作放在了锁持有区间,所有线程被迫串行执行,完全没有并发效果
- 消费退出逻辑只判断了已消费数量,没有结合生产完成状态,逻辑不严谨
修复方案
- 新增全局生产完成标记,生产者结束生产后更新标记并唤醒所有消费者
- 消费者等待条件新增生产完成状态判断,确认无新餐品且缓冲区为空时直接退出
- 把生产、消费的耗时sleep移到锁外,符合真实业务逻辑同时提升并发效率
- 消费完成后调用
notify_all保证等待的生产者能被正确唤醒
修复后完整代码
#include <iostream> #include <vector> #include <chrono> #include <thread> #include <mutex> #include <deque> #include <condition_variable> std::mutex semaforo; std::condition_variable notifica; std::deque<int> buffer; const unsigned int capacidade_buffer = 10; const unsigned int numero_pratos = 25; bool production_finished = false; // 新增生产完成标记 void produtor() { unsigned int contador_pratos_produzidos = 0; while (contador_pratos_produzidos < numero_pratos) { // 生产耗时放在锁外,不阻塞其他线程 std::this_thread::sleep_for(std::chrono::microseconds(50)); std::unique_lock<std::mutex> locker(semaforo); notifica.wait(locker, [] { return buffer.size() < capacidade_buffer; }); buffer.push_back(contador_pratos_produzidos); contador_pratos_produzidos++; locker.unlock(); notifica.notify_all(); } // 生产全部完成,更新标记并唤醒所有消费者 { std::lock_guard<std::mutex> locker(semaforo); production_finished = true; } notifica.notify_all(); } void consumidor(int ID, std::vector<int> &consumido) { unsigned int contador_pratos_consumidos = 0; while (true) { std::unique_lock<std::mutex> locker(semaforo); // 等待条件新增生产完成判断 notifica.wait(locker, [] { return buffer.size() > 0 || production_finished; }); // 生产结束且缓冲区为空,直接退出 if (production_finished && buffer.empty()) { locker.unlock(); break; } // 缓冲区有餐品,执行消费 buffer.pop_front(); contador_pratos_consumidos++; consumido[ID]++; locker.unlock(); notifica.notify_all(); // 配送耗时放在锁外,不阻塞其他线程 std::this_thread::sleep_for(std::chrono::microseconds(15)); } } int main() { std::vector<int> consumido(6, 0); std::vector<std::thread> consumidores; for (int k = 0; k < 6; k++) { consumidores.push_back(std::thread(consumidor, k, std::ref(consumido))); } std::thread p1(produtor); for (auto &k : consumidores) { k.join(); } p1.join(); int mais_ocioso = 200, menos_ocioso = 0, mais, menos; for (int k = 0; k < 6; k++) { std::cout << "Garcon " << k + 1 << " entregou " << consumido[k] << " pratos\n"; if (consumido[k] > menos_ocioso) { menos = k + 1; menos_ocioso = consumido[k]; } if (consumido[k] < mais_ocioso) { mais = k + 1; mais_ocioso = consumido[k]; } } std::cout << "\nO mais ocioso foi o garcon " << mais << " e o menos ocioso foi o garcon " << menos << "\n"; return 0; }
内容的提问来源于stack exchange,提问作者Assis Gabriel
相关产品推荐
相关产品推荐

