如何用C++11线程等待多线程完成?多线程阻塞问题求助
问题分析与解决方案
首先,你的代码里存在几个关键问题导致多线程测试时程序无法正常结束,我来逐一拆解:
核心问题点
- 条件变量与互斥锁不配对:在
wait()方法中,你使用了m_waitForRunFinishMutex来配合m_cond.wait(),但在run()方法里,却是用m_mutex来调用m_cond.wait()。条件变量的设计要求必须和同一个互斥锁绑定使用,否则会触发未定义行为,这是导致producer2无法被正确唤醒的主要原因之一。 - 虚假唤醒的处理逻辑错误:原
wait()里用if (m_running)后递归调用wait(),这种方式不仅会导致锁的管理混乱,还无法可靠处理条件变量的虚假唤醒。正确的做法是用while循环持续检查条件,直到满足退出条件。 wait()方法的递归调用风险:递归调用wait()会导致多次加锁(虽然你手动解锁了,但逻辑上依然混乱),很容易引发死锁或者唤醒失效的问题。
修正后的代码实现
针对这些问题,我们主要修正wait()方法,同时确保条件变量和互斥锁的配对使用:
#include <iostream> #include <thread> #include <condition_variable> #include <mutex> using namespace std; class Producer { public: Producer(int a_id): m_id(a_id), m_running(false), m_ready(false), m_terminate(false) { m_thread = thread(&Producer::run, this); while (!m_ready) {} } ~Producer() { terminate(); m_thread.join(); } void wait() { unique_lock<mutex> lock(m_mutex); // 和run()里用同一个锁 // 用while循环处理虚假唤醒,直到m_running变为false while (m_running) { m_cond.wait(lock); } cout << "wait exit " << m_id << endl; } void start() { unique_lock<mutex> lock(m_mutex); m_running = true; m_cond.notify_all(); } void terminate() { unique_lock<mutex> lock(m_mutex); m_terminate = true; m_running = true; // 确保线程能从wait中唤醒 m_cond.notify_all(); } void run() { m_ready = true; do { unique_lock<mutex> lock(m_mutex); while (!m_running) { m_cond.wait(lock); } if (!m_terminate) { cout << "running thread: " << m_id << endl; } m_running = false; m_cond.notify_all(); } while (!m_terminate); } private: int m_id; bool m_running; bool m_ready; bool m_terminate; thread m_thread; mutex m_mutex; // 只保留一个锁,和条件变量配对 condition_variable m_cond; }; // 测试代码 int main() { Producer producer1(1); Producer producer2(2); producer1.start(); producer2.start(); producer1.wait(); producer2.wait(); return 0; }
修正说明
- 移除了多余的
m_waitForRunFinishMutex,统一使用m_mutex和m_cond配对,确保条件变量的操作都是基于同一个锁。 - 重构
wait()方法,使用while循环检查m_running状态,正确处理虚假唤醒,同时避免递归调用。 - 在
start()和terminate()方法中也添加了锁保护,确保对共享变量m_running和m_terminate的修改是线程安全的。
运行修正后的代码,你会得到预期的输出:
running thread: 1 running thread: 2 wait exit 1 wait exit 2
内容的提问来源于stack exchange,提问作者Gio
相关产品推荐
相关产品推荐

