linux barrier 栅栏屏障,让多任务在栅栏处集合,全部到齐后同时出发

news2024/10/10 2:20:09

专栏内容
postgresql内核源码分析
手写数据库toadb
并发编程
个人主页:我的主页
座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物.

==================================

概述

pthread_barrier_t 这是posix定义线程同步方法,不一定所有linux 版本中都实现了它。

barrier 是一种非常有效的线程同步方法,当我们需要几个线程一起开始时,或者在某个条件下需要一起等待时,
就需要有个类似栅栏一样的东西,条件成立时,就会被拦住。

当然这个功能,也可能通过管道,信号量,eventfd等方法实现,但是barrier非常简单高效。

接口

/* 头文件 */
#include <pthread.h>

/* 初始化接口 */ 
int pthread_barrier_init(pthread_barrier_t *restrict barrier,
           const pthread_barrierattr_t *restrict attr, unsigned count);

/* 销毁接口,资源回收 */ 
int pthread_barrier_destroy(pthread_barrier_t *barrier);

/* 栅栏接口,调用者会阻塞,直到调用次数达到 count值后,所有阻塞都会放开 */
int pthread_barrier_wait(pthread_barrier_t *barrier); 

接口说明

  1. pthread_barrier_init接口会初始化所需资源;

如果attr传入为NULL时,采用默认值进行初始化;

count ,是指调用 pthread_barrier_wait多少次,才能成功返回;其值必须大于0 ;

只有返回成功,才是初始化完成;

  • 返回码
  • EAGAIN 系统资源不足

  • EINVAL 非法入参,count必须大于0

  • ENOMEM 内存不足
  1. pthread_barrier_destroy 接口销毁所有barrier上分配的资源
  1. pthread_barrier_wait 会设置屏障栅栏,所有调用处都会被阻塞住,直到调用次数到达count值时,才会继续执行;

对于超过count的调用,不会被阻栏,那么它们有可能会先于栅栏阻塞的线程执行;这是由系统调度来决定的;

当调用达到count次数后,又会被重置;

注意事项

  • pthread_barrier_t使用前必须初始化,否则行为是未定义的;

  • 当正在使用的pthread_barrier_t 调用了 pthread_barrier_destroy,后面的行为也是未定义的;

尤其是,当有线程阻塞在 barrier上时;

  • 当正在使用的pthread_barrier_t调用了pthread_barrier_init,那就会被重新初始化,后面的行为也是未定义的;

正此种情况下,对于 pthread_barrier_wait 调用不会返回;

  • 这些接口不会返回 EINTR 错误码;

  • pthread_barrier_wait 如果遇到信号中断处理,对于已经被阻塞的线程中有正在处理信号,

如果还没有到达count,信号处理返回后会继续等待;

如果信号处理过程中,已经到达count,那么所有阻塞线程,在信号处理完成后,才会一起放开执行;

举例

代码

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

#define THEAD_COUNT 10
#define THRED_WAIT_COUNT 3

pthread_barrier_t start_barrier;
int index[THEAD_COUNT];

void* func(void *data)
{
    int i = *(int *)data;
    int wait = i/THRED_WAIT_COUNT * 1000;

    printf("threads %p starting %d \n", pthread_self(), i);

    /* thread-0 will wait longer time than the other threads. */
    usleep(wait);

    pthread_barrier_wait(&start_barrier);

    printf("threads %p running %d \n", pthread_self(), i);
}

int main(int argc, char *argv[])
{
    int ret;
    int count = THRED_WAIT_COUNT;
    int i = 0;
    pthread_t threads[THEAD_COUNT];

    pthread_barrier_init(&start_barrier, NULL, count);

    for (i = 0; i < THEAD_COUNT; i++)
    {
        index[i] = i;
        ret = pthread_create(&threads[i], NULL, func, (void*)&index[i]);
        if (ret != 0) 
        {
            printf("failed to create thread: %d\n", i);
        }
    }

    for (i = 0; i < THEAD_COUNT; i++)
    {
        ret = pthread_join(threads[i], NULL);
        if (ret != 0) 
        {
            printf("failed to join thread: %d\n", i);
        }
    }

    printf("all threads exited \n");
    pthread_barrier_destroy(&start_barrier);
    return 0;
}

  • 代码说明

在代码中启动了10个线程,但是设置barrier的count只有3个

也就是说只需要凑够3个线程,就可以开启了;
这就像我们报名参赛,每组需要3个人,那么凑够三个人的组就可以开始比赛了,还没凑够的就不能比赛;

编译

[senllang@hatch barrier]$ gcc ex01_barrier.c -lpthread -o barrier

多线程,在编译时,需要加线程库 -lpthread

运行结果

[senllang@hatch barrier]$ ./barrier
threads 0x7fc85a523700 starting 0
threads 0x7fc859d22700 starting 1
threads 0x7fc859521700 starting 2
threads 0x7fc850d20700 starting 3
threads 0x7fc858d20700 starting 4
threads 0x7fc859521700 running 2
threads 0x7fc85a523700 running 0
threads 0x7fc859d22700 running 1
threads 0x7fc853fff700 starting 5
threads 0x7fc8537fe700 starting 6
threads 0x7fc852ffd700 starting 7
threads 0x7fc8527fc700 starting 8
threads 0x7fc851ffb700 starting 9
threads 0x7fc853fff700 running 5
threads 0x7fc850d20700 running 3
threads 0x7fc858d20700 running 4
threads 0x7fc8527fc700 running 8
threads 0x7fc8537fe700 running 6
threads 0x7fc852ffd700 running 7
^C
[senllang@hatch barrier]$

  • 运行结果说明

在代码中,为了分组明显,传入了每个线程的序号,根据序号每组等待的时间不同;

可以看到每三个是一组,到达三的倍数时,就开始有starting的线程

但是最后有两个线程,凑不够三个,所以一直没有开始运行

只能用ctrl+c强制停止了

结尾

非常感谢大家的支持,在浏览的同时别忘了留下您宝贵的评论,如果觉得值得鼓励,请点赞,收藏,我会更加努力!

作者邮箱:study@senllang.onaliyun.com
如有错误或者疏漏欢迎指出,互相学习。

注:未经同意,不得转载!

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

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

相关文章

Windows电脑应用设置开机自启动

背景 比如我们程序员&#xff0c;开机就想电脑自启动谷歌浏览器和VS Code等开发工具&#xff0c;自己什么都不用动&#xff0c;怎么办&#xff1f;有人说可以在任务管理器的启动里设置&#xff0c;但还是有些工具里面没有的&#xff0c;也就是不能这样设置的&#xff0c;今天教…

Windows环境下git客户端中的git-bash和MinGW64

我们在 Windows10 操作系统下&#xff0c;安装了 git 客户端之后&#xff0c;可以通过 git-bash.exe 打开一个 shell&#xff1a; 执行一些 linux 系统里的命令&#xff1a; 注意到上图紫色的 MINGW64. Mingw-w64 是原始 mingw.org 项目的改进版&#xff0c;旨在支持 Window…

数据结构【线性表】

数据结构入门级 第二章 线性表 一、线性表的定义和基本操作 线性表的定义&#xff1a;具有相同属性数据类型的数据元素组成的一个有限序列&#xff1b;除第一个元素外的元素都有直接前驱&#xff0c;除最后一个元素外的元素都有直接后继&#xff1b;存在一个唯一被称为“第一个…

【ARM Coresight 系列文章 10.3 - ARM Coresight STM 寄存器介绍 及STM DMA 传输介绍】

文章目录 STM Register summarySTM DMA 相关的寄存器DMA TransferBurst requestSingle and burst request STM Register summary STM 的寄存器主要可以分为以下几类&#xff1a; STM DMA 相关的&#xff1b;STM HW Trigger 相关的&#xff1b;系统控制及状态寄存器&#xff1…

CSS布局定位+装饰

一、定位 1.1 网页常见布局方式 1. 标准流 1. 块级元素独占一行 → 垂直布局 2. 行内元素/行内块元素一行显示多个 → 水平布局 2. 浮动 1. 可以让原本垂直布局的 块级元素变成水平布局 3. 定位 1. 可以让元素自由的摆放在网页的任意位置 2. 一般用于 盒子之间的层叠情…

Java的运行时数据区域

Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域有各自的用途&#xff0c;以及创建和销毁的时间&#xff0c;有些区域随着虚拟机进程的启动而一直存在&#xff0c;有些区域则是依赖用户线程的启动和结束而建立和销毁。 根据《Jav…

OpenAI宣布安卓版ChatGPT正式上线;一站式 LLM底层技术原理入门指南

&#x1f989; AI新闻 &#x1f680; OpenAI宣布安卓版ChatGPT正式上线 摘要&#xff1a;OpenAI今日宣布&#xff0c;安卓版ChatGPT已正式上线&#xff0c;目前美国、印度、孟加拉国和巴西四国的安卓用户已可在谷歌Play商店下载&#xff0c;并计划在下周拓展到更多地区。Chat…

VMware Network Adapter VMnet1和VMnet8 未识别的网络问题

在安装虚拟机的时候使用的网络类型未NAT模式&#xff0c;但是却无法和外部网络ping通&#xff0c;并且使用Xshell进行连接反应也非常慢&#xff1b;于是在我查询半天问题之后&#xff0c;这个问题得到了解决&#xff0c;具体如下&#xff1a; 在使用NAT网络模式的时候需要进行…

【portswigger】第二专题-XSS(二)

portswigger 靶场&#xff08;第二章节&#xff09;XSS 视频同步更新至bilibili bibi地址欢迎关注微信公众号&#xff1a;微光安全团队 这是官方备忘录&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet总体目录 我这里简单总结一下每个…

nodejs+vue+elementui高校科研队伍管理系统_2byeq

系统阐述的是使用科研管理系统&#xff0c;对于nodejs、B/S结构、MySql进行了较为深入的学习与应用。主要针对系统的设计&#xff0c;描述&#xff0c;实现和分析与测试方面来表明开发的过程。开发中使用了vue框架和MySql数据库技术搭建系统的整体架构。利用这些技术结合实际需…

【Haclon】Liunx每个月过期了怎么使用

Liunx每个月过期怎么使用 1.去gitHub进行下载2. 下载最新的Halcon_licenses3.进行替换 1.去gitHub进行下载 https://github.com/lovelyyoshino/Halcon_licenses 2. 下载最新的Halcon_licenses sudo vim ~/.bashrc找到/opt/halcon 3.进行替换 /opt/halcon/license 将这个目…

百万数据分页查询优化方案

分页问题 分页列表查询是项目中的热点需求&#xff0c;这种需求的特点是&#xff1a;字段多、数据量大、访问频繁、使用率高的特点&#xff0c;这个功能是给用户最直观的展示系统的信息&#xff0c;针对于多、大、频、热这几个特点&#xff0c;会引申出一个问题&#xff1a;列…

swmm模型城市内涝一维二维耦合;海绵城市+SWMM完整版教程

随着计算机的广泛应用和各类模型软件的发展&#xff0c;将排水系统模型作为城市洪灾评价与防治的技术手段已经成为防洪防灾的重要技术途径。本次将聚焦于综合利用GIS及CAD等工具高效地进行大规模城市排水系统水力模型的建立&#xff0c;利用SWMM实现排水系统水力模拟。讲解SWMM…

el-table 表格头部合并

<el-table v-loading"listLoading" :key"tableKey" :data"list" stripe border fit highlight-current-rowstyle"width: 100%;" size"mini"><el-table-column label"第一行" align"center">…

Windows 安装 Redis5

Windows 安装 Redis5 安装包 Redis for Windows 5.0.14.1 https://github.com/tporadowski/redis/releases/tag/v5.0.14.1 安装教程 选择安装路径&#xff0c;并勾选下方&#xff0c;将 Redis 添加到系统环境变量 这个是 Redis 默认的端口号&#xff0c;无特殊需求不用改 设置…

ES6 模块编程(新思路方便复习笔记)

文章目录 ES6 模块编程(新思路方便复习笔记)介绍需求说明思路分析/图解代码实现创建common.js创建use_common.js 其它导出形式--直接导出创建common2.js创建use_common2.js 其它导出形式--默认导出创建common3.js创建use_common3.js--导入默认导出模块/数据注意事项和使用细节导…

毓恬冠佳冲刺上市:打破汽车天窗外商垄断,长安汽车为其主要客户

撰稿|行星 来源|贝多财经 7月23日&#xff0c;上海毓恬冠佳科技股份有限公司&#xff08;以下简称“毓恬冠佳”&#xff09;在深圳证券交易所的审核状态变更为“已问询”。据贝多财经了解&#xff0c;毓恬冠佳于2023年6月27日递交招股书&#xff0c;准备在创业板上市。 本次冲…

十一、数据结构——树(Tree)的基本概念

数据结构之树(Tree) 目录 树的基本概念树的分类树的基本操作树的应用结语 树的基本概念 树是一种重要的数据结构&#xff0c;它在计算机科学中被广泛应用。树的特点是以分层的方式存储数据&#xff0c;具有层次结构&#xff0c;类似于现实生活中的树状结构。在树中&#xff…

环境变量初始化与对应文件的生效顺序

正常登陆情况下&#xff08;不是系统启动过程而是输入用户名和密码登录时&#xff0c;或者注销用户重新登录&#xff09;&#xff0c;环境变量配置文件的调用过程&#xff1a; // 正常登陆时环境变量配置文件的调用过程 /etc/profile|--/etc/profile.d/*|--/etc/profile.d/lan…

设计模式---综合应用-自定义Spring框架-自定义Spring IOC-定义解析器、IOC容器相关类

3 定义解析器相关类 3.1 BeanDefinitionReader接口 BeanDefinitionReader是用来解析配置文件并在注册表中注册bean的信息。定义了两个规范&#xff1a; 获取注册表的功能&#xff0c;让外界可以通过该对象获取注册表对象。 加载配置文件&#xff0c;并注册bean数据。 /*** …