在Linux系统中提供了多种同步机制,本文主要讲讲如何使用pthread_barrier_xxx
系列函数来实现多线程之间进行同步的方法。
函数定义
pthread_barrier_xxx
系列函数中的barrier可意为栅栏,可以理解为该栅栏能够把先后到达的多个线程阻挡在同一栅栏前,直到所有线程到齐,栅栏才会放行,否则到达此处的线程将被阻塞。
pthread_barrier_xxx
系列函数在<pthread.h>
文件中定义,用于多线程的同步,该系列函数主要包含下列三个函数:
// 初始化栅栏,负责指定栅栏要等待的线程个数,
// 栅栏需要等待count个线程都到达栅栏时,才会全部一起放行
int pthread_barrier_init(pthread_barrier_t *restrict,
const pthread_barrierattr_t *restrict, unsigned count);
// pthread_barrier_wait()函数会同步所有参与barrier的线程,
// 调用该函数的线程会阻塞住,直到pthread_barrier_init()中指定
// 数量的线程调用了pthread_barrier_wait()函数,所有线程才会同时往下执行
int pthread_barrier_wait(pthread_barrier_t *barrier);
// 释放pthread_barrier_init()函数申请的资源
int pthread_barrier_destroy(pthread_barrier_t *barrier);
应用场景
在应用程序启动的时候,需要创建一个或者多个线程去完成不同功能的处理。子线程启动之后,需要等待主进程完成基础的配置之后各个子线程才能正常工作。所以这里就存在一个问题要解决,各个子线程如何等待主进程完成工作后,才继续往下执行呢?
为了解决上述场景的问题,我们可以在调用pthread_barrier_init()
时指定n+1个等待,其中n是线程数。而在每个线程执行函数的开始调用pthread_barrier_wait()
。这样主进程在调用pthread_create()
创建子线程后,子线程运行到pthread_barrier_wait()
后将被阻塞,线程都停下来等待最后一个pthread_barrier_wait()
函数被调用。最后一个pthread_barrier_wait()
函数由主进程或者其他子线程在它觉得合适的时候调用就行。最后这个pthread_barrier_wait()
有点像跑步运动时的起步枪,只有最后这个pthread_barrier_wait()
函数被调用,其他被阻塞的线程就能够继续运行。
使用实例
下面的程序,在main()
函数中,pthread_barrier_init()
指定2+1个等待,接着创建了2个线程,然后主进程延时6秒,之后调用pthread_barrier_wait()
来让线程接着运行,程序如下:
/*
********************************************************************************
*描述:pthread_barrier_xxx程序示例
*Use:gcc pthread_barrier_xxx.c -lpthread
* ./a.out
*By:Ailson Jack
*Date:2016.03.24
*CSDN:https://blog.csdn.net/jackailson
********************************************************************************
*/
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
// 线程栅栏
pthread_barrier_t barrier;
void *task1(void *arg);
void *task2(void *arg);
int main(void)
{
pthread_t task1_tid;
pthread_t task2_tid;
pthread_attr_t task1_attr;
pthread_attr_t task2_attr;
// 初始化线程属性
pthread_attr_init(&task1_attr);
pthread_attr_init(&task2_attr);
// 初始化栅栏
pthread_barrier_init(&barrier, NULL, 2+1); // 2+1 个等待
// 创建线程1
pthread_create(&task1_tid, &task1_attr, task1, NULL);
// 创建线程2
pthread_create(&task2_tid, &task2_attr, task2, NULL);
printf("main process will sleep 6s.\r\n");
sleep(6); // 等待6s,让task1和task2都阻塞住了,再运行主线程
// 主线程调用pthread_barrier_wait()函数之后,已经达到了
// pthread_barrier_init()函数设置的3个等待条件,此时调用
// pthread_barrier_wait()函数的主线程不会被阻塞,task1和
// task2也将继续运行.
pthread_barrier_wait(&barrier);
pthread_join(task1_tid, NULL);
pthread_join(task2_tid, NULL);
pthread_barrier_destroy(&barrier);
}
void *task1(void *arg)
{
printf("task1 will be blocked.\r\n");
pthread_barrier_wait(&barrier); // 线程将被阻塞在这里
printf("task1 is running.\r\n");
sleep(3); // 延时3s
pthread_exit(NULL);
}
void *task2(void *arg)
{
printf("task2 will be blocked.\r\n");
pthread_barrier_wait(&barrier); // 线程将被阻塞在这里
printf("task2 is running.\r\n");
sleep(3); // 延时3s
pthread_exit(NULL);
}
程序的运行结果如下图所示:
如果文中有什么问题欢迎指正,毕竟博主的水平有限。
如果这篇文章对你有帮助,记得点赞和关注博主就行了。
注:转载请注明出处,谢谢!