C++ Mutex与条件变量同步问题:主线程等待循环工作子线程执行完成
问题原因
- 工作线程更新
finished标记为true后没有触发条件变量通知,主线程的wait调用收不到唤醒信号,永久挂起。 - 主线程持有互斥锁的状态下执行
sleep,导致所有工作线程无法拿到锁进入下一轮等待,属于逻辑错误。 - 循环变量重名:main函数中,外层循环变量
i被内层重置finished数组的循环变量i覆盖,会导致外层循环执行次数异常。 - 单一条件变量同时承载「工作线程等待任务」和「主线程等待完成」两类等待逻辑,容易出现信号互扰。
修复方案
- 新增独立条件变量
cv_main专门用于主线程等待工作线程完成任务,避免信号冲突。 - 工作线程完成任务修改
finished标记后,主动调用条件变量通知唤醒主线程。 - 缩小互斥锁的作用范围,主线程等待完成后立刻释放锁,再执行休眠逻辑。
- 修正循环变量重名问题,避免外层循环逻辑异常。
- 补充全量
finished状态校验逻辑,确保主线程等待所有工作线程执行完成后再继续。
修正后完整代码
#include <iostream> // std::cout #include <thread> // std::thread #include <mutex> // std::mutex, std::unique_lock #include <condition_variable> // std::condition_variable #include <Windows.h> #define N 3 std::mutex mtx; std::condition_variable cv; // 用于工作线程等待任务触发 std::condition_variable cv_main; // 用于主线程等待任务全部完成 bool finished[N]; void print_id(int id) { while (1) { std::unique_lock<std::mutex> lck(mtx); // 等待任务触发:finished[id]为false时开始执行 while (finished[id]) cv.wait(lck); // 任务逻辑 std::cout << "thread " << id << '\n'; // 标记当前线程任务完成 finished[id] = true; // 通知主线程检查完成状态 cv_main.notify_all(); } } int main() { std::thread threads[N]; for (int i = 0; i < N; ++i) { threads[i] = std::thread(print_id, i); finished[i] = true; // 初始状态标记为已完成,等待触发 } std::cout << N << " threads ready to race...\n"; for (int i = 0; i < 5; i++) { // 把锁的作用域限制在任务触发+等待完成阶段 { std::unique_lock<std::mutex> lck(mtx); // 重置所有线程完成标记,允许开始执行 for (int j = 0; j < N; j++) { finished[j] = false; } // 通知所有工作线程开始执行 cv.notify_all(); // 等待所有工作线程完成本次任务 cv_main.wait(lck, [] { for (int k = 0; k < N; k++) { if (!finished[k]) return false; } return true; }); } // 锁已经释放,工作线程可以进入下一轮等待,主线程休眠 std::cout << "round " << i << " finished, Sleeping for 2s\n"; Sleep(2000); } // 实际使用时需要补充退出逻辑通知工作线程结束,此处省略 return 0; }
内容的提问来源于stack exchange,提问作者Ashley Cusack
相关产品推荐
相关产品推荐

