0


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

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

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

概述

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

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

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

接口

/* 头文件 */#include<pthread.h>/* 初始化接口 */intpthread_barrier_init(pthread_barrier_t*restrict barrier,constpthread_barrierattr_t*restrict attr,unsigned count);/* 销毁接口,资源回收 */intpthread_barrier_destroy(pthread_barrier_t*barrier);/* 栅栏接口,调用者会阻塞,直到调用次数达到 count值后,所有阻塞都会放开 */intpthread_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上分配的资源

  2. 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>#defineTHEAD_COUNT10#defineTHRED_WAIT_COUNT3pthread_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);}intmain(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);return0;}
  • 代码说明

在代码中启动了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
如有错误或者疏漏欢迎指出,互相学习。

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


本文转载自: https://blog.csdn.net/senllang/article/details/131930485
版权归原作者 韩楚风 所有, 如有侵权,请联系我们删除。

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

还没有评论