请求用std::condition_variable实现latch的arrive_and_wait(C++17环境)
用C++17实现Latch的arrive_and_wait方法(替代忙等)
问题背景
项目基于C17开发,无法使用C20的std::latch,需要用std::condition_variable实现arrive_and_wait方法,替换原代码中的忙等循环,确保"done 1""done 2""done 3"能同时输出。
修改后的完整代码
#include <atomic> #include <condition_variable> #include <limits> #include <chrono> #include <cstddef> #include <cstdlib> #include <iostream> #include <future> #include <thread> class Latch { public: Latch(void) : expected(0) {} void count_up(void) { if(expected < std::numeric_limits<Count>::max()) expected++; else { std::cerr<<"#Error! Latch::count_up: expected: "<<expected<<std::endl; exit(EXIT_FAILURE); } } void arrive_and_wait(void) { // 原子操作减少计数,获取减之前的值 auto current = expected--; // 不是最后一个到达的线程,进入等待 if (current > 1) { std::unique_lock<std::mutex> lock(mutex); // 带条件等待,避免虚假唤醒 cond.wait(lock, [this]{ return expected.load() == 0; }); } // 最后一个到达的线程,唤醒所有等待线程 else if (current == 1) { std::lock_guard<std::mutex> lock(mutex); cond.notify_all(); } } private: using Count = uint_fast8_t; std::atomic<Count> expected; std::condition_variable cond; // 新增互斥锁,与condition_variable配合保证线程安全 std::mutex mutex; }; void Run(const int delayInSeconds, Latch * const latch=nullptr) { if(latch) latch->count_up(); std::this_thread::sleep_for( std::chrono::seconds(delayInSeconds) ); if(latch) latch->arrive_and_wait(); } int main(void) { std::cout<<"start...\n"; Latch latch; auto f1 = std::async(Run, 2, &latch); auto f2 = std::async(Run, 4, &latch); auto f3 = std::async(Run, 8, &latch); f1.get(); std::cout<<"done 1\n"; f2.get(); std::cout<<"done 2\n"; f3.get(); std::cout<<"done 3\n"; return EXIT_SUCCESS; }
关键修改说明
- 新增互斥锁:
std::condition_variable必须与std::mutex配合使用,避免竞态条件和虚假唤醒问题,保证线程安全。 - 原子计数操作:
expected为原子变量,expected--是原子操作,确保多线程环境下计数修改的正确性。 - 等待与唤醒逻辑:
- 非最后到达的线程会进入等待状态,直到计数变为0;
- 最后一个到达的线程负责唤醒所有等待的线程,确保所有线程同时继续执行,实现预期的同步效果。
- 防虚假唤醒:
cond.wait使用带条件的重载,每次被唤醒都会检查expected是否为0,避免因系统虚假唤醒导致的错误执行。
内容的提问来源于stack exchange,提问作者S.V
相关产品推荐
相关产品推荐

