贝利信息

c++20的std::barrier和std::latch如何用于线程同步? (多线程协作)

日期:2026-01-13 00:00 / 作者:尼克
该用std::latch时用于一次性同步,如主线程等待所有工作线程完成;该用std::barrier时用于多轮循环同步,如并行迭代中每轮等待所有线程到达。

std::barrierstd::latch 是 C++20 引入的轻量级同步原语,专为“等待一组线程到达某个点”而设计。它们比 std::mutex + std::condition_variable 更简洁、更高效,且无所有权语义(不绑定线程),适合一次性或循环式协作场景。

什么时候该用 std::latch

std::latch 是一次性计数器:初始化后只能递减(count_down())和等待(wait()),不可重置、不可重复使用。典型用于“主线程等所有工作线程完成”这类单次汇聚场景。

std::latch done(3);
std::thread t1([&]{ /* work */ done.count_down(); });
std::thread t2([&]{

/* work */ done.count_down(); }); std::thread t3([&]{ /* work */ done.count_down(); });

done.wait(); // 主线程阻塞,直到三次 count_down 完成 t1.join(); t2.join(); t3.join();

什么时候该用 std::barrier

std::barrier 是可重用的同步点,每次所有参与线程调用 arrive()(或 arrive_and_wait())后自动重置计数,进入下一轮。适合多阶段并行计算,比如迭代算法中的每轮同步。

std::barrier sync(4);
std::vector workers;
for (int i = 0; i < 4; ++i) {
    workers.emplace_back([&sync]{
        for (int round = 0; round < 3; ++round) {
            // 每轮独立计算
            do_work(round);
            sync.arrive_and_wait(); // 等其他 3 个线程也到达
        }
    });
}
for (auto& t : workers) t.join();

为什么不用 std::condition_variable 替代?

不是不能,而是容易出错且冗余。用条件变量模拟 latch 需要手动管理互斥量、计数器、通知逻辑;模拟 barrier 还得处理重入、唤醒丢失、虚假唤醒等问题。

实际协作中容易忽略的细节

两者都要求所有参与线程**严格调用相同次数**的同步操作,否则要么永远等待,要么未定义行为。没有运行时校验,编译器也不会报错。