标准库标头 <barrier>(C++20)学习

news2024/9/21 17:59:35

此头文件是线程支持库的一部分。

类模板 std::barrier 提供一种线程协调机制,阻塞已知大小的线程组直至该组中的所有线程到达该屏障。不同于 std::latch,屏障是可重用的:一旦到达的线程组被解除阻塞,即可重用同一屏障。与 std::latch 不同,会在线程解除阻塞前执行一个可能为空的可调用对象。

屏障对象的生存期由一个或多个屏障阶段组成。每个阶段定义一个阻塞线程的阶段同步点。线程可以抵达屏障,但通过调用 arrive 来推迟它在阶段同步点上的等待。这样的线程可以随后再通过调用 wait 在阶段同步点上阻塞。

屏障 阶段 由以下步骤组成:

  1. 每次调用 arrive 或 arrive_and_drop 减少期待计数
  2. 期待计数抵达零时,运行阶段完成步骤,即调用 completion,并解除所有在阶段同步点上阻塞的线程。完成步骤的结束强先发生于所有从完成步骤所除阻的调用的返回。
    在期待计数抵达零后,一个线程会在其调用 arrive、arrive_and_drop 或 wait 的过程中执行完成步骤恰好一次,但如果没有线程调用 wait 则是否执行完成步骤为实现定义。
  3. 完成步骤结束时,重置期待计数为构造中指定的值,它可能为 arrive_and_drop 调用所调整,自此开始下一阶段。

并发调用barrier 除了析构函数外的成员函数不会引起数据竞争。

vs2022 类模板如下:

class barrier {
public:
    static_assert(
#ifndef __cpp_noexcept_function_type
        is_function_v<remove_pointer_t<_Completion_function>> ||
#endif // !defined(__cpp_noexcept_function_type)
            is_nothrow_invocable_v<_Completion_function&>,
        "N4950 [thread.barrier.class]/5: is_nothrow_invocable_v<CompletionFunction&> shall be true");

    using arrival_token = _Arrival_token<_Completion_function>;

    constexpr explicit barrier(
        const ptrdiff_t _Expected, _Completion_function _Fn = _Completion_function()) noexcept /* strengthened */
        : _Val(_One_then_variadic_args_t{}, _STD move(_Fn), _Expected << _Barrier_value_shift) {
        _STL_VERIFY(_Expected >= 0 && _Expected <= (max) (),
            "Precondition: expected >= 0 and expected <= max() (N4950 [thread.barrier.class]/9)");
    }

    barrier(const barrier&)            = delete;
    barrier& operator=(const barrier&) = delete;

    _NODISCARD static constexpr ptrdiff_t(max)() noexcept {
        return _Barrier_max;
    }

    _NODISCARD_BARRIER_TOKEN arrival_token arrive(ptrdiff_t _Update = 1) noexcept /* strengthened */ {
        _STL_VERIFY(_Update > 0 && _Update <= (max) (), "Precondition: update > 0 (N4950 [thread.barrier.class]/12)");
        _Update <<= _Barrier_value_shift;
        // TRANSITION, GH-1133: should be memory_order_release
        ptrdiff_t _Current = _Val._Myval2._Current.fetch_sub(_Update) - _Update;
        _STL_VERIFY(_Current >= 0, "Precondition: update is less than or equal to the expected count "
                                   "for the current barrier phase (N4950 [thread.barrier.class]/12)");
        if ((_Current & _Barrier_value_mask) == 0) {
            // TRANSITION, GH-1133: should have this fence:
            // atomic_thread_fence(memory_order_acquire);
            _Completion(_Current);
        }
        // Embedding this into the token to provide an additional correctness check that the token is from the same
        // barrier and wasn't used. All bits of this fit, as barrier should be aligned to at least the size of an
        // atomic counter.
        return arrival_token{(_Current & _Barrier_arrival_token_mask) | reinterpret_cast<intptr_t>(this)};
    }

    void wait(arrival_token&& _Arrival) const noexcept /* strengthened */ {
        _STL_VERIFY((_Arrival._Value & _Barrier_value_mask) == reinterpret_cast<intptr_t>(this),
            "Preconditions: arrival is associated with the phase synchronization point for the current phase "
            "or the immediately preceding phase of the same barrier object (N4950 [thread.barrier.class]/19)");
        const ptrdiff_t _Arrival_value = _Arrival._Value & _Barrier_arrival_token_mask;
        _Arrival._Value                = _Barrier_invalid_token;
        for (;;) {
            // TRANSITION, GH-1133: should be memory_order_acquire
            const ptrdiff_t _Current = _Val._Myval2._Current.load();
            _STL_VERIFY(_Current >= 0, "Invariant counter >= 0, possibly caused by preconditions violation "
                                       "(N4950 [thread.barrier.class]/12)");
            if ((_Current & _Barrier_arrival_token_mask) != _Arrival_value) {
                break;
            }
            _Val._Myval2._Current.wait(_Current, memory_order_relaxed);
        }
    }

    void arrive_and_wait() noexcept /* strengthened */ {
        // TRANSITION, GH-1133: should be memory_order_acq_rel
        ptrdiff_t _Current       = _Val._Myval2._Current.fetch_sub(_Barrier_value_step) - _Barrier_value_step;
        const ptrdiff_t _Arrival = _Current & _Barrier_arrival_token_mask;
        _STL_VERIFY(_Current >= 0, "Precondition: update is less than or equal to the expected count "
                                   "for the current barrier phase (N4950 [thread.barrier.class]/12)");
        if ((_Current & _Barrier_value_mask) == 0) {
            _Completion(_Current);
            return;
        }

        for (;;) {
            _Val._Myval2._Current.wait(_Current, memory_order_relaxed);
            // TRANSITION, GH-1133: should be memory_order_acquire
            _Current = _Val._Myval2._Current.load();
            _STL_VERIFY(_Current >= 0, "Invariant counter >= 0, possibly caused by preconditions violation "
                                       "(N4950 [thread.barrier.class]/12)");
            if ((_Current & _Barrier_arrival_token_mask) != _Arrival) {
                break;
            }
        }
    }

    void arrive_and_drop() noexcept /* strengthened */ {
        const ptrdiff_t _Rem_count =
            _Val._Myval2._Total.fetch_sub(_Barrier_value_step, memory_order_relaxed) - _Barrier_value_step;
        _STL_VERIFY(_Rem_count >= 0, "Precondition: The expected count for the current barrier phase "
                                     "is greater than zero (N4950 [thread.barrier.class]/24) "
                                     "(checked initial expected count, which is not less than the current)");
        (void) arrive(1);
    }

private:
    void _Completion(const ptrdiff_t _Current) noexcept {
        const ptrdiff_t _Rem_count = _Val._Myval2._Total.load(memory_order_relaxed);
        _STL_VERIFY(_Rem_count >= 0, "Invariant: initial expected count less than zero, "
                                     "possibly caused by preconditions violation "
                                     "(N4950 [thread.barrier.class]/24)");
        _Val._Get_first()();
        const ptrdiff_t _New_phase_count = _Rem_count | ((_Current + 1) & _Barrier_arrival_token_mask);
        // TRANSITION, GH-1133: should be memory_order_release
        _Val._Myval2._Current.store(_New_phase_count);
        _Val._Myval2._Current.notify_all();
    }

    struct _Counter_t {
        constexpr explicit _Counter_t(ptrdiff_t _Initial) : _Current(_Initial), _Total(_Initial) {}
        // wait(arrival_token&&) accepts a token from the current phase or the immediately preceding phase; this means
        // we can track which phase is the current phase using 1 bit which alternates between each phase. For this
        // purpose we use the low order bit of _Current.
        atomic<ptrdiff_t> _Current;
        atomic<ptrdiff_t> _Total;
    };

    _Compressed_pair<_Completion_function, _Counter_t> _Val;
};

成员对象

名称定义
completion (私有)CompletionFunction 类型的完成函数对象,在每个阶段完成步骤调用。
(仅用于阐述的成员对象*)

成员类型

名称定义
arrival_token未指定的对象类型,满足可移动构造 (MoveConstructible) 、可移动赋值 (MoveAssignable) 及可析构 (Destructible) 

成员函数

(构造函数)

构造 barrier
(公开成员函数)

(析构函数)

销毁 barrier
(公开成员函数)

operator=

[弃置]

barrier 不可赋值
(公开成员函数)

arrive

到达屏障并减少期待计数
(公开成员函数)

wait

在阶段同步点阻塞,直至运行其阶段完成步骤
(公开成员函数)

arrive_and_wait

到达屏障并把期待计数减少一,然后阻塞直至当前阶段完成
(公开成员函数)

arrive_and_drop

将后继阶段的初始期待计数和当前阶段的期待计数均减少一
(公开成员函数)
常量

max

[静态]

实现所支持的期待计数的最大值
(公开静态成员函数)

示例代码:

#include <barrier>
#include <iostream>
#include <string>
#include <syncstream>
#include <thread>
#include <vector>


int main()
{
    const auto workers = { "Anil", "Busara", "Carl" };

    auto on_completion = []() noexcept
        {
            // 此处无需锁定
            static auto phase =
                "... 完成\n"
                "清理...\n";
            std::cout << phase;
            phase = "... 完成\n";
        };

    std::barrier sync_point(std::ssize(workers), on_completion);

    auto work = [&](std::string name)
        {
            std::string product = "  " + name + " 已工作\n";
            std::osyncstream(std::cout) << product;  // OK, op<< 的调用是原子的
            sync_point.arrive_and_wait();

            product = "  " + name + " 已清理\n";
            std::osyncstream(std::cout) << product;
            sync_point.arrive_and_wait();
        };

    std::cout << "启动...\n";
    std::vector<std::jthread> threads;
    threads.reserve(std::size(workers));
    for (auto const& worker : workers)
        threads.emplace_back(work, worker);

    return 0;
}

运行结果:

另一个示例:

#include <barrier>
#include <iostream>
#include <string>
#include <syncstream>
#include <thread>
#include <vector>


std::barrier bar(4); //创建一个barrier,需要4个线程到达同步点

void thread_func(int id) {
    // 线程执行一些任务
    //std::cout << "Thread ID: " << std::this_thread::get_id() << " is doing some work." << std::endl;
    std::cout << "Thread ID=======start===== is doing some work.\n";

    // 等待所有线程到达栅栏
    bar.arrive_and_wait();

    // 所有线程到达栅栏后,继续执行后续任务
    //std::cout << "Thread ID: " << std::this_thread::get_id() << " continues working after barrier." << std::endl;
    std::cout << "Thread ID=======end: ===== continues working after barrier.\n";
}

int main() {
    constexpr int num_threads = 4;
    std::vector<std::thread> threads;

    // 创建线程并执行线程函数
    for (int i = 0; i < num_threads; ++i) {
        threads.emplace_back(thread_func, i);
    }

    // 等待所有线程执行完毕
    for (auto& t : threads) {
        t.join();
    }

    return 0;
}

示例代码:

#include <barrier>
#include <iostream>
#include <string>
#include <syncstream>
#include <thread>
#include <vector>


std::barrier bar(4); //创建一个barrier,需要4个线程到达同步点

void thread_func(int id) {
    // 线程执行一些任务
    //std::cout << "Thread ID: " << std::this_thread::get_id() << " is doing some work." << std::endl;
    std::cout << "Thread ID=======start===== is doing some work.\n";

    // 等待所有线程到达栅栏
    bar.arrive_and_wait();

    // 所有线程到达栅栏后,继续执行后续任务
    //std::cout << "Thread ID: " << std::this_thread::get_id() << " continues working after barrier." << std::endl;
    std::cout << "Thread ID=======end: ===== continues working after barrier.\n";
}

int main() {
    constexpr int num_threads = 4;
    std::vector<std::thread> threads;

    // 创建线程并执行线程函数
    for (int i = 0; i < num_threads; ++i) {
        threads.emplace_back(thread_func, i);
    }

    // 等待所有线程执行完毕
    for (auto& t : threads) {
        t.join();
    }

    return 0;
}

运行结果:

参考:

std::barrier - cppreference.com

【C++ 20 并发工具 std::barrier】掌握并发编程:深入理解C++的std::barrier_c++ barrier-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2127345.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

django自用教程

编程软件: pycharm django介绍:django是Pythonweb的一个框架&#xff0c;是用来构建网站的工具。 要想使用django&#xff0c;首先需要下载django模块&#xff0c;通过使用以下代码实现: pip install django 安装完成后&#xff0c;在django的目录下有一个文件django-admin&am…

Docker启动Mysql镜像报错问题?

docker中启动mysql镜像报错如下&#xff1a;ls: cannot access /docker-entrypoint-initdb.d/: Operation not permitted 百度上查到了很多解决方案&#xff0c;也咨询了很多大佬&#xff0c;加权限&#xff0c;改用户&#xff0c;均无果。最终在阿里巴巴上找到了解决方案&…

【有啥问啥】深入理解数据结构 Merkle 树:数据完整性保障的基石

深入理解 Merkle 树&#xff1a;数据完整性保障的基石 在当今的分布式系统和区块链应用中&#xff0c;数据的完整性验证变得至关重要。随着区块链技术、分布式存储系统&#xff08;如 IPFS&#xff09;、以及版本控制系统&#xff08;如 Git&#xff09;的大规模应用&#xff…

【Linux】文件权限与类型全解:你的文件安全指南

欢迎来到 CILMY23 的博客 &#x1f3c6;本篇主题为&#xff1a;文件权限与类型全解&#xff1a;你的文件安全指南 &#x1f3c6;个人主页&#xff1a;CILMY23-CSDN博客 &#x1f3c6;系列专栏&#xff1a;Python | C | C语言 | 数据结构与算法 | 贪心算法 | Linux | 算法专题…

kubectl 命令介绍以及使用

文章目录 kubectl 基本命令查看集群信息管理命名空间操作节点 操作 Pods查看 Pods 状态创建和删除 Pods调试 Pods 操作 Deployments创建 Deployment更新 Deployment回滚 Deployment 操作 Services暴露服务查看服务状态 更多 kubectl 命令资源描述资源过滤日志查看配置上下文和切…

热门语音转文字工具大比拼

现在工作、生活的节奏越来越快&#xff0c;很多时候会议上并没有充足的时间来记录会议内容&#xff0c;最快捷的方式就是用录音来记录每一个观点。录音文件后期转化为文字需要花费大力气吗&#xff1f;并不是&#xff0c;现在有着讯飞语音转文字这类高速高效的转换工具可以轻松…

PMP–一、二、三模–分类–13.干系人管理--技巧--1、干系人分析

文章目录 二模13.干系人管理--干系人分析--题干关键词 “干系人信息&#xff08;权力、角色、利益、关系、态度、影响……&#xff09;、识别完干系人、某干系人抵制项目”。5、 [单选] 一家公司启动了一个与开发新服务相关的项目&#xff0c;而该公司并不具有此类专业知识。项…

分布式集群下如何做到唯一序列号

优质博文&#xff1a;IT-BLOG-CN 分布式架构下&#xff0c;生成唯一序列号是设计系统常常会遇到的一个问题。例如&#xff0c;数据库使用分库分表的时候&#xff0c;当分成若干个sharding表后&#xff0c;如何能够快速拿到一个唯一序列号&#xff0c;是经常遇到的问题。实现思…

【AI赋能医学】基于深度学习和HRV特征的多类别心电图分类

一、数据集简介 论文中使用了来自三类不同心电图记录的162条数据&#xff0c;这些数据来自三个公开的数据库&#xff1a; MIT-BIH 心律失常数据库 (ARR) 96条记录&#xff0c;主要包含不同类型的心律失常样本。 MIT-BIH 正常窦性心律数据库 (NSR) 36条记录&#xff0c;包含健…

【springboot】简易模块化开发项目整合MyBatis-plus

接父子工程项目搭建&#xff0c;继续扩展项目 重新调整模块结构 1.删除子模块fast-demo-web中所有无用内容 2.右键fast-demo-web名称->新建&#xff08;news&#xff09;->模块&#xff08;Module&#xff09;&#xff0c;创建新的子模块 3.选择新建Maven工程 4.新建模…

STMCubeMX文件下载后会出现其他项目无法下载的问题

一、问题 二、解决方法 ①、对箭头所指处画√ ②、按住复位键不要松开&#xff0c;你点击下载&#xff0c;1s左右松开即可发现可以重新下载了

计算机毕业设计 教务管理系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

GD32F4开发 -- JLink使用

之前写过 STM32开发 – Jlink常用命令 &#xff0c;今天遇到需要SEGGER RTT 配置&#xff0c;就再写一下吧。 一、下载并安装JLink 下载&#xff1a; J-Link / J-Trace Downloads 可选择需要的版本下载&#xff1a; 二、SEGGER RTT 包含文件 得到 SEGGER_RTT_V794m.zip …

KTV 包房订房登记表—SAAS本地化及未来之窗行业应用跨平台架构

一、服务员点单 二、服务员自己点单好处 可以自动计算绩效和提成 三、阿雪技术观 拥抱开源与共享&#xff0c;见证科技进步奇迹&#xff0c;畅享人类幸福时光&#xff01; 让我们积极投身于技术共享的浪潮中&#xff0c;不仅仅是作为受益者&#xff0c;更要成为贡献者。无论是…

scene graph generation 计算mean recall数据的过程:

这里写目录标题 前言&#xff1a;计算mean recall的详细过程1. **准备数据**&#xff1a;2. **计算每个类别的recall**&#xff1a;具体代码片段准备groundtruth数据准备预测数据计算recall计算mean recall 前言&#xff1a; 计算流程这里参考maskrcnn_benchmark/data/dataset…

为AppInventor2开发自己的拓展(Extension) - 拓展开发入门篇

//为什么需要开发拓展&#xff1f;// App Inventor 2 是积木式在线安卓开发环境&#xff0c;利用拖拽式的方式实现代码块堆叠&#xff0c;从而完成相应的逻辑。 上手很容易&#xff0c;但是由于代码块提供的功能有限&#xff0c;使用比较单一&#xff0c;在开发上有很大的局限…

计算机视觉的应用32-基于Swin Transformer模型的嵌入混合注意力机制的人脸表情识别的应用

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下计算机视觉的应用32-基于Swin Transformer模型的嵌入混合注意力机制的人脸表情识别的应用。随着深度学习技术的不断演进&#xff0c;计算机视觉领域迎来了诸多变革&#xff0c;其中 Transformer 架构的引入&#xf…

脑电实验打mark【Eprim中打mark】

文章目录 脑电实验打mark一、端口号查询二、并口打mark 脑电实验打mark 一、端口号查询 右击我的电脑–>管理–>设备管理器–>端口 二、并口打mark 在整个流程最前面添加inline控件&#xff1a; 需要打mark的控件名.onsetsignalenabledTrue //去送信 需要打mark的…

助力汽车零部件产业发展,2025 第十二届广州国际汽车零部件加工技术及汽车模具展览会与您相约“羊城”广州

助力汽车零部件产业发展&#xff0c;2025 第十二届广州国际汽车零部件加工技术及汽车模具展览会与您相约“羊城”广州 汽车零部件是支撑汽车工业持续健康发展的必要因素&#xff0c;为汽车的正常运行和安全性能提供了保障。近年来&#xff0c;中国汽车零部件行业受到各级政府的…

基于SpringBoot+Vue的线上考试系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的线上考试…