0

0

c++的std::barrier如何用于实现多线程的集合点同步? (栅栏)

穿越時空

穿越時空

发布时间:2026-01-13 12:59:02

|

763人浏览过

|

来源于php中文网

原创

std::barrier是C++20引入的循环同步原语,适用于多线程分阶段协作场景,如并行计算的每轮迭代同步;它支持自动重置,需精确指定并确保恰好N个线程调用wait()。

c++的std::barrier如何用于实现多线程的集合点同步? (栅栏)

std::barrier 是什么,适合在哪种同步场景用

std::barrier 是 C++20 引入的线程同步原语,专为「多个线程在某个点集体等待、全部到达后才一起继续」这种集合点(rendezvous)场景设计。它比 std::condition_variable + std::mutex 更轻量,也比反复轮询或 std::latch(仅能触发一次)更贴合循环协作模式。

典型适用场景:多线程并行计算中需要分阶段执行,比如每轮迭代开始前所有线程必须完成上一轮工作;或模拟物理仿真中每个时间步所有线程更新完状态再统一推进。

如何正确构造和调用 barrier.wait()

构造时需指定预期到达的线程数(expected),该值不可变。每次调用 barrier.wait() 会阻塞当前线程,直到第 expected 个线程抵达 —— 此时所有等待线程被同时唤醒,且 barrier 自动重置为下一轮等待(这是它和 std::latch 的关键区别)。

  • 必须确保**恰好**有 expected 个线程调用 wait(),少一个会永久挂起,多一个会触发未定义行为(通常 crash 或死锁)
  • 同一个 std::barrier 对象可被重复使用,无需重建
  • 不支持超时等待(C++20 标准中无 try_wait_for 等变体),如需超时需自行封装
std::barrier b{4}; // 期待 4 个线程到达
std::vector threads;
for (int i = 0; i < 4; ++i) {
    threads.emplace_back([&b, i] {
        // 每个线程做些事
        do_work(i);
        // 到达集合点
        b.wait(); // 阻塞直到第 4 个线程也调用 wait()
        // 所有线程在此处之后并发继续
        continue_processing(i);
    });
}
for (auto& t : threads) t.join();

为什么不能用 std::latch 替代 barrier 实现循环同步

std::latch 是一次性门闩:构造时设 count,每次 count_down() 减一,减到零后所有等待者被唤醒,但之后再调用 wait() 会立即返回,无法重置。而 std::barrier 在每次全员到达后自动归零并重置计数器,天然适配多轮同步。

Rationale
Rationale

Rationale 是一款可帮助企业主、经理和个人做出艰难的决定的AI工具

下载

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

  • 若强行用 std::latch 做多轮同步,你得在每轮开始前 new 一个新 latch,或手动管理生命周期,极易出错
  • std::barrierarrive() 成员函数允许提前通知到达(不阻塞),配合 wait() 可实现更灵活的协调逻辑(例如某些线程只报告不等待)
  • 底层实现上,barrier 通常比反复构造 latch 更高效,避免内存分配和销毁开销

常见误用与崩溃原因

实际写代码时最容易栽在生命周期和调用次数上:

  • std::barrier 对象必须**在线程调用 wait() 期间持续有效** —— 如果它是个局部变量,而主线程在子线程还在 wait() 时就退出了作用域,会导致未定义行为(常见 SIGSEGV)
  • 误把 barrier.arrive() 当作 wait() 使用:前者只递减计数并返回新计数值,不阻塞;若只调 arrive() 不调 wait(),其他线程会在 wait() 处永远等不到第 expected 个到达
  • 跨线程传递 barrier 时用了裸指针或引用,但源对象已析构,尤其在 lambda 捕获时容易忽略捕获方式:[&b][b] 安全,但更要确保 b 的生存期覆盖所有线程

复杂点在于:barrier 的语义干净,但它的正确性完全依赖程序员对线程数量和生命周期的手动保证,编译器和运行时几乎不帮你检查。稍不留神,就是静默死锁或随机崩溃。

相关专题

更多
counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

197

2023.11.20

lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

204

2023.09.15

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

190

2025.11.08

Python lambda详解
Python lambda详解

本专题整合了Python lambda函数相关教程,阅读下面的文章了解更多详细内容。

45

2026.01.05

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

480

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

143

2025.12.24

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

143

2025.12.24

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

1

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

5

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
10分钟--Midjourney创作自己的漫画
10分钟--Midjourney创作自己的漫画

共1课时 | 0.1万人学习

Midjourney 关键词系列整合
Midjourney 关键词系列整合

共13课时 | 0.9万人学习

AI绘画教程
AI绘画教程

共2课时 | 0.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号