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

news/2024/11/18 17:49:48/

专栏内容
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 3pthread_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.ppmy.cn/news/988126.html

相关文章

奥迪A3:最新款奥迪A3内饰设计及智能科技应用

奥迪A3一直以来都是奥迪的入门级车型&#xff0c;但这并不意味着它在科技和内饰方面会有所退步。最新款奥迪A3的内饰设计和智能科技应用让人们再次惊叹奥迪的创新能力。 内饰设计 奥迪A3最新款的内饰设计引入了奥迪最新的设计元素&#xff0c;比如8.8英寸的中控显示屏&#xf…

开发一个RISC-V上的操作系统(四)—— 内存管理

目录 往期文章传送门 一、内存管理简介 二、Linker Script 链接脚本 三、动态分配内存 四、测试 往期文章传送门 开发一个RISC-V上的操作系统&#xff08;一&#xff09;—— 环境搭建_riscv开发环境_Patarw_Li的博客-CSDN博客 开发一个RISC-V上的操作系统&#xff08;二…

json.stringify的高级用法,和for of的原理

** /* for of 是用来循环可迭代属性的,如何判断是否是可迭代属性,数据原型链上有个Symbol.iterator说明这个数据是可迭代数据 Symbol.iterator是一个函数,调用此函数,会返回一个对象,对象的内部有一个next函数,调用next函数会返回一个对象这个对象内部有value和done值&#xf…

centos7安装git

方式一: 输入命令安装 直接使用命令即可 下载的可能是旧版 yum install -y git验证是否安装成功 git --version方式二&#xff1a;解压包安装 获取要下载的版本安装包 然后上传至服务器 如果安装了旧版可以使用 卸载 yum remove git 创建 文件夹 mkdir -p /usr/local/git…

优思学院:六西格玛的10大概念和特点

六西格玛是一种管理方法&#xff0c;致力于提高组织的运营效率和质量水平。它起源于20世纪80年代的美国&#xff0c;随后在全球范围内得到广泛应用。今天我们将探讨六西格玛的十大概念和特点&#xff0c;帮助您了解如何将这一管理方法应用于您的业务中。 1. 什么是六西格玛&am…

教雅川学缠论02-K线

传统行情上的K线是下图中这样子的 而在缠论中K线是下面这样子的&#xff0c;它没有上影线和下影线 下图是武汉控股2023年7月的日K线 接下来我们将它转换成缠论K线&#xff08;画图累死我了&#xff09; K线理解了我们才能进行下一步&#xff0c;目前位置应该很好理解的

PyTorch BatchNorm2d详解

通常和卷积层&#xff0c;激活函数一起使用

docker安装rabbitmq

1&#xff0c;拉取rabbitmq容器 docker pull rabbitmq 2&#xff0c;下载完以后启动容器 先查看自己的容器id&#xff1a; [rootch ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE rabbitmq latest bcef1e…