如何用C++ std::thread实现线程全完成Part1后再执行Part2?
多线程同步:所有线程完成Part1后再执行Part2
问题分析
你需要实现的是**线程屏障(Barrier)**机制:让所有线程在执行Part2前,必须等待其他线程全部完成Part1。你之前用mutex+原子变量的方案逻辑存在缺陷——仅让最后一个线程执行unlock,但其他线程已经调用lock且没有唤醒逻辑,导致它们一直阻塞无法继续。
可行解决方案
方案1:使用C++20的std::barrier(推荐)
C++20引入的std::barrier专门处理这类“所有线程到达同步点后再统一继续”的场景,用法简洁高效:
首先在类中定义共享的barrier对象:
#include <barrier> class TMainForm { private: std::barrier<>* threadBarrier = nullptr; public: void foo(int numThreads); void StartingThreads(); };
修改函数实现:
void TMainForm::foo(int numThreads) { std::cout << "Part 1: do some work" << std::endl; // 等待所有线程完成Part1 threadBarrier->arrive_and_wait(); std::cout << "Part 2: do some work" << std::endl; } void TMainForm::StartingThreads() { int threads = std::thread::hardware_concurrency(); // 初始化barrier,指定需要等待的线程总数 threadBarrier = new std::barrier<>(threads); std::vector<std::thread> t(threads); for (int i = 0; i < threads; i++) t[i] = std::thread(&TMainForm::foo, this, threads); for (auto& th : t) th.join(); delete threadBarrier; threadBarrier = nullptr; }
方案2:使用std::condition_variable + std::mutex + 原子变量(兼容C++11/17)
如果你的环境不支持C++20,可以用条件变量手动实现屏障逻辑:
在类中添加共享同步变量:
#include <condition_variable> #include <atomic> class TMainForm { private: std::mutex mtx; std::condition_variable cv; std::atomic<int> completedPart1 = 0; int totalThreads = 0; public: void foo(); void StartingThreads(); };
修改函数实现:
void TMainForm::foo() { std::cout << "Part 1: do some work" << std::endl; // 原子递增完成Part1的线程数 int current = completedPart1.fetch_add(1) + 1; std::unique_lock<std::mutex> lock(mtx); // 非最后完成的线程,等待通知 if (current < totalThreads) { cv.wait(lock, [this](){ return completedPart1 == totalThreads; }); } else { // 最后一个线程完成,唤醒所有等待的线程 cv.notify_all(); } std::cout << "Part 2: do some work" << std::endl; } void TMainForm::StartingThreads() { totalThreads = std::thread::hardware_concurrency(); completedPart1 = 0; // 重置计数器 std::vector<std::thread> t(totalThreads); for (int i = 0; i < totalThreads; i++) t[i] = std::thread(&TMainForm::foo, this); for (auto& th : t) th.join(); }
原方案失败原因
你之前的逻辑是让未完成全部Part1的线程调用mutex::lock,但缺少唤醒机制:一旦某个线程成功lock,其他线程会持续卡在lock调用处;即使最后一个线程执行unlock,也只有一个线程能继续,剩余线程仍会阻塞。正确的做法是用条件变量等待,当所有线程完成Part1后统一唤醒,而非用mutex的lock/unlock控制执行流程。
内容的提问来源于stack exchange,提问作者TommyBe
相关产品推荐
相关产品推荐

