std::latch是c++20引入的一次性同步屏障,用于让线程等待预设数量的到达事件(如worker初始化完成)后统一继续执行;适用于主线程等待多个子线程就绪、或协调所有线程同时开始等单次同步场景。

std::latch 是什么,什么时候该用它
std::latch 是 C++20 引入的轻量级同步原语,专为“一次性等待多个线程到达同一屏障点”设计。它不支持重置,也不支持多次等待 —— 用完即弃。如果你要实现的是“所有工作线程就绪后,统一发令开始执行”,std::latch 比 std::barrier 更合适(后者支持重复使用),也比手写 std::condition_variable + std::mutex 简洁安全。
典型场景:主线程启动 N 个 worker 线程,每个 worker 初始化完后调用 arrive();主线程在所有 worker 就绪前阻塞在 wait() 上,等齐了再发任务。
如何正确初始化和使用 std::latch
构造时必须指定计数值(count),代表需要多少次 arrive() 才能解除阻塞。这个值不能为 0(否则构造抛 std::system_error);也不能中途修改 —— 它是只读的。
-
std::latch latch(4);表示等待 4 次arrive() - 每个 worker 线程调用
latch.arrive();(注意:不是arrive(1)—— C++20 的std::latch::arrive()不带参数) - 主线程调用
latch.wait();阻塞直到计数归零 - 一旦
wait()返回,所有后续调用wait()或arrive()的行为都是未定义的(不要复用)
常见错误:忘记传引用或移动语义搞错
多线程环境下,std::latch 对象必须被所有线程共享访问 —— 通常通过引用或指针传递。如果按值传给 lambda 或线程函数,会触发拷贝(而 std::latch 禁止拷贝),编译直接失败:
std::latch latch(3);
std::thread t1([latch]() { latch.arrive(); }); // ❌ 编译错误:latch 不可拷贝
正确做法:
- 用
[&latch]捕获引用(最常用) - 或用
std::ref(latch)传参:std::thread t1([](std::latch& l) { l.arrive(); }, std::ref(latch)); - 切记:
std::latch不可移动(C++20 标准中显式删除了移动构造/赋值),所以也不能用std::move试图转移所有权
与 std::barrier 和 std::semaphore 的关键区别
别混淆这三个 C++20 同步工具:
-
std::latch:一次性,无回调,不可重用 —— 适合“启动门控” -
std::barrier:可重用,支持到达时执行回调(如 barrier phase completion),适合循环同步点(如多轮迭代) -
std::counting_semaphore:通用信号量,支持 acquire/release、可设初始值、可跨线程多次使用 —— 但开销略大,且需手动管理资源
如果你只是想让一堆线程“一起起步”,std::latch 是最直白、最低开销的选择;但一旦需要第二次同步,就得换 std::barrier —— 别硬撑着 reset 或重建 std::latch,那会引入竞态。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











