C++怎么使用latch_C++20同步原语教程【协调】

1次阅读

std::latch 必须在构造时用非零正整数初始化,如 std::latch l(3);不支持默认构造、零初始化、重置或拷贝,仅适用于一次性同步场景。

C++怎么使用latch_C++20同步原语教程【协调】

std::latch 在 c++20 中怎么初始化才不会崩溃

必须在构造时指定计数值,且不能为 0;否则触发未定义行为(常见于调试器报 std::system_error 或直接 abort)。它不支持默认构造、也不支持运行时重新设置计数。

  • std::latch 只能用 count 初始化: std::latch l(3); ✅,std::latch l; ❌,std::latch l(0);
  • 计数值是只读的,没有 set_count()reset() 成员函数;需要重复使用请换 std::barrier
  • 线程l.wait() 前就调用 l.count_down() 多次导致计数归零,wait() 会立即返回 —— 这是正常行为,不是 bug

std::latch.wait() 被卡住?检查线程是否真的调用了 count_down

l.wait() 是阻塞同步点,但不会自动唤醒;它只依赖计数是否降到 0。如果漏掉某处 count_down(),或该调用被条件分支跳过,主线程就会永久挂起(无超时机制)。

  • 典型误用:if (ready) l.count_down(); 却没保证所有路径都执行 —— 改成 l.count_down(); 放在确定执行的位置
  • l.count_down() 是无锁、原子、常量时间操作,可安全从任意线程多次调用(即使已为 0)
  • 没有 try_wait() 或带超时的 wait_for();如需防死锁,得自己套 std::condition_variable + std::mutex,此时不如直接用后者

std::latch 和 std::barrier 的核心区别在哪

两者都用于线程协同,但语义完全不同:std::latch 是一次性“门闩”,std::barrier 是可重用的“路障”。选错会导致逻辑错误或编译失败。

  • std::latch:计数到 0 后不可重置,适合“等 N 个任务全部完成”这种单次场景(如启动阶段初始化)
  • std::barrier:构造时也传 count,但提供 arrive()(等价 count_down())和自动重置能力;适用于循环协作(如多线程分块计算每轮同步)
  • 二者都不支持 notify_one()接口;也没有所有权转移语义 —— std::latch 不可拷贝、不可移动,只能按值传递(实际是禁止的),通常作为局部变量成员变量持有

链接时提示 undefined reference to std::latch::wait

不是代码写错了,是编译器/标准库没真正启用 C++20 同步支持。Clang/GCC 需显式链接 libstdc++libc++ 的新版本,且头文件包含不等于符号可用。

立即学习C++免费学习笔记(深入)”;

  • 确认编译选项含 -std=c++20-std=gnu++20 也可,但避免混用)
  • MSVC 2019 16.11+ / GCC 11+ / Clang 12+ 才完整支持;旧版即使加了 #include <latch></latch> 也会链接失败
  • linux 下若用系统自带 GCC 10,可能需手动安装 libstdc++-11-dev 并指定 -I/usr/include/c++/11-L/usr/lib/gcc/x86_64-linux-gnu/11

真正容易被忽略的是:它不抛异常来告诉你计数用错了,也不会在 debug 模式下做额外检查 —— 错了就是静默 UB 或卡死。用之前先想清楚,这道门是不是真的只需要关一次。

text=ZqhQzanResources