屏障

屏障是多线程同步的一种方法。barrier意为屏障或者栏杆,把先后到达的多个线程挡在同一栏杆前,直到所有线程到齐,然后撤下栏杆同时放行。先到达的线程将会阻塞,等到所有调用pthread_barrier_wait()函数的线程(数量等于屏障初始化时指定的count)都到达后,这些线程才会由阻塞状态进入就绪状态再次参与系统调度。

屏障是基于条件变量和互斥锁实现的。主要操作包括:调用pthread_barrier_init()初始化一个屏障,其他线程调用pthread_barrier_wait(),所有线程到期后线程唤醒进入准备状态,屏障不在使用调用pthread_barrier_destroy()销毁一个屏障。

屏障控制块

创建一个屏障前需要先定义一个pthread_barrier_t屏障控制块。pthread_barrier_t是pthread_barrier结构体类型的重定义,定义在pthread.h头文件里。

  1. struct pthread_barrier
  2. {
  3. int count; /*指定的等待线程个数*/
  4. pthread_cond_t cond; /* 条件变量 */
  5. pthread_mutex_t mutex; /* 互斥锁 */
  6. };
  7. typedef struct pthread_barrier pthread_barrier_t;

创建屏障

函数原型

  1. int pthread_barrier_init(pthread_barrier_t *barrier,
  2. const pthread_barrierattr_t *attr,
  3. unsigned count);

  1. 参数 描述

  1. attr 指向屏障属性的指针,传入NULL,则使用默认值,非NULL必须使用PTHREAD_PROCESS_PRIVATE
  2.  
  3. barrier 屏障句柄
  4.  
  5. count 指定的等待线程个数

函数返回

初始化成功返回0,参数无效返回EINVAL。

此函数会创建一个barrier屏障,并根据默认的参数对屏障控制块的条件变量和互斥锁初始化,初始化后指定的等待线程个数为count个,必须对应count个线程 调用pthread_barrier_wait()。

attr一般设置NULL使用默认值即可,具体会在线程高级编程一章介绍。

销毁屏障

函数原型

  1. int pthread_barrier_destroy(pthread_barrier_t *barrier);

  1. 参数 描述

  1. barrier 屏障句柄

函数返回

销毁成功返回0,参数无效返回EINVAL。

此函数会销毁一个barrier屏障。销毁之后屏障的属性及控制块参数将不在有效,但可以调用pthread_barrier_init()重新初始化。

等待屏障

函数原型

  1. int pthread_barrier_wait(pthread_barrier_t *barrier);

  1. 参数 描述

  1. barrier 屏障句柄

函数返回

等待成功返回0,参数无效返回EINVAL,死锁返回EDEADLK。

此函数同步等待在barrier前的线程,由每个线程主动调用,若屏障等待线程个数count不为0,count将减1,若减1后count为0,表明所有线程都已经到达栏杆前,所有到达的线程将被唤醒重新进入就绪状态,参与系统调度。若减一后count不为0,表明还有线程没有到达屏障,调用的线程将阻塞直到所有线程到达屏障。

屏障示例代码

此程序会创建3个线程,初始化一个屏障,屏障等待线程数初始化为3。3个线程都会调用pthread_barrier_wait()等待在屏障前,当3个线程都到齐后,3个线程进入就绪态,之后会每隔2秒打印输出计数信息。

  1. #include <pthread.h>
  2. #include <unistd.h>
  3. #include <stdio.h>
  4.  
  5. /* 线程控制块 */
  6. static pthread_t tid1;
  7. static pthread_t tid2;
  8. static pthread_t tid3;
  9. /* 屏障控制块 */
  10. static pthread_barrier_t barrier;
  11. /* 函数返回值检查函数 */
  12. static void check_result(char* str,int result)
  13. {
  14. if (0 == result)
  15. {
  16. printf("%s successfully!\n",str);
  17. }
  18. else
  19. {
  20. printf("%s failed! error code is %d\n",str,result);
  21. }
  22. }
  23. /*线程1入口函数*/
  24. static void* thread1_entry(void* parameter)
  25. {
  26. int count = 0;
  27.  
  28. printf("thread1 have arrived the barrier!\n");
  29. pthread_barrier_wait(&barrier); /* 到达屏障,并等待其他线程到达 */
  30.  
  31. while (1)
  32. {
  33. /* 打印线程计数值输出 */
  34. printf("thread1 count: %d\n",count ++);
  35.  
  36. /* 休眠2秒*/
  37. sleep(2);
  38. }
  39. }
  40. /*线程2入口函数*/
  41. static void* thread2_entry(void* parameter)
  42. {
  43. int count = 0;
  44.  
  45. printf("thread2 have arrived the barrier!\n");
  46. pthread_barrier_wait(&barrier);
  47.  
  48. while (1)
  49. {
  50. /* 打印线程计数值输出 */
  51. printf("thread2 count: %d\n",count ++);
  52.  
  53. /* 休眠2秒*/
  54. sleep(2);
  55. }
  56. }
  57. /* 线程3入口函数 */
  58. static void* thread3_entry(void* parameter)
  59. {
  60. int count = 0;
  61.  
  62. printf("thread3 have arrived the barrier!\n");
  63. pthread_barrier_wait(&barrier);
  64.  
  65. while (1)
  66. {
  67. /* 打印线程计数值输出 */
  68. printf("thread3 count: %d\n",count ++);
  69.  
  70. /* 休眠2秒*/
  71. sleep(2);
  72. }
  73. }
  74. /* 用户应用入口 */
  75. int rt_application_init()
  76. {
  77. int result;
  78. pthread_barrier_init(&barrier,NULL,3);
  79.  
  80. /*创建线程1,线程入口是thread1_entry, 属性参数设为NULL选择默认值,入口参数为NULL*/
  81. result = pthread_create(&tid1,NULL,thread1_entry,NULL);
  82. check_result("thread1 created",result);
  83.  
  84. /*创建线程2,线程入口是thread2_entry, 属性参数设为NULL选择默认值,入口参数为NULL*/
  85. result = pthread_create(&tid2,NULL,thread2_entry,NULL);
  86. check_result("thread2 created",result);
  87.  
  88. /*创建线程3,线程入口是thread3_entry, 属性参数设为NULL选择默认值,入口参数为NULL*/
  89. result = pthread_create(&tid3,NULL,thread3_entry,NULL);
  90. check_result("thread3 created",result);
  91.  
  92. }