linux线程同步(5)-屏障
一.概述 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
barrier(屏障)與互斥量,讀寫鎖,自旋鎖不同,它不是用來保護(hù)臨界區(qū)的。相反,它跟條件變量一樣,是用來協(xié)同多線程一起工作!!!
條件變量是多線程間傳遞狀態(tài)的改變來達(dá)到協(xié)同工作的效果。屏障是多線程各自做自己的工作,如果某一線程完成了工作,就等待在屏障那里,直到其他線程的工作都完成了,再一起做別的事。舉個(gè)通俗的例子:
1.對于條件變量。在接力賽跑里,1號隊(duì)員開始跑的時(shí)候,2,3,4號隊(duì)員都站著不動,直到1號隊(duì)員跑完一圈,把接力棒給2號隊(duì)員,2號隊(duì)員收到接力棒后就可以跑了,跑完再給3號隊(duì)員。這里這個(gè)接力棒就相當(dāng)于條件變量,條件滿足后就可以由下一個(gè)隊(duì)員(線程)跑。
2.對于屏障。在百米賽跑里,比賽沒開始之前,每個(gè)運(yùn)動員都在賽場上自由活動,有的熱身,有的喝水,有的跟教練談?wù)摗1荣惪扉_始時(shí),準(zhǔn)備完畢的運(yùn)動員就預(yù)備在起跑線上,如果有個(gè)運(yùn)動員還沒準(zhǔn)備完(除去特殊情況),他們就一直等,直到運(yùn)動員都在起跑線上,裁判喊口號后再開始跑。這里的起跑線就是屏障,做完準(zhǔn)備工作的運(yùn)動員都等在起跑線,直到其他運(yùn)動員也把準(zhǔn)備工作做完!
二.函數(shù)接口 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
1.創(chuàng)建屏障
1 #include <pthread.h> 2 3 int pthread_barrier_init(pthread_barrier_t *restrict barrier, const pthread_barrierattr_t *restrict attr, unsigned count);barrier:pthread_barrier_t結(jié)構(gòu)體指針
attr:屏障屬性結(jié)構(gòu)體指針
count:屏障等待的線程數(shù)目,即要count個(gè)線程都到達(dá)屏障時(shí),屏障才解除,線程就可以繼續(xù)執(zhí)行
2.等待
1 #include <pthread.h> 2 3 int pthread_barrier_wait(pthread_barrier_t *barrier);函數(shù)的成功返回值有2個(gè),第一個(gè)成功返回的線程會返回PTHREAD_BARRIER_SERIAL_THREAD,其他線程都返回0。可以用第一個(gè)成功返回的線程來做一些善后處理工作。
3.銷毀屏障
1 #include <pthread.h> 2 3 int pthread_barrier_destroy(pthread_barrier_t *barrier);三.簡單例子 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
寫個(gè)簡單的例子,主線程等待其他線程都完成工作后自己再向下執(zhí)行,類似pthread_join()函數(shù)!
1 /** 2 * @file pthread_barrier.c 3 */ 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <unistd.h> 9 #include <pthread.h> 10 11 /* 屏障總數(shù) */ 12 #define PTHREAD_BARRIER_SIZE 4 13 14 /* 定義屏障 */ 15 pthread_barrier_t barrier; 16 17 void err_exit(const char *err_msg) 18 { 19 printf("error:%s\n", err_msg); 20 exit(1); 21 } 22 23 void *thread_fun(void *arg) 24 { 25 int result; 26 char *thr_name = (char *)arg; 27 28 /* something work */ 29 30 printf("線程%s工作完成...\n", thr_name); 31 32 /* 等待屏障 */ 33 result = pthread_barrier_wait(&barrier); 34 if (result == PTHREAD_BARRIER_SERIAL_THREAD) 35 printf("線程%s,wait后第一個(gè)返回\n", thr_name); 36 else if (result == 0) 37 printf("線程%s,wait后返回為0\n", thr_name); 38 39 return NULL; 40 } 41 42 int main(void) 43 { 44 pthread_t tid_1, tid_2, tid_3; 45 46 /* 初始化屏障 */ 47 pthread_barrier_init(&barrier, NULL, PTHREAD_BARRIER_SIZE); 48 49 if (pthread_create(&tid_1, NULL, thread_fun, "1") != 0) 50 err_exit("create thread 1"); 51 52 if (pthread_create(&tid_2, NULL, thread_fun, "2") != 0) 53 err_exit("create thread 2"); 54 55 if (pthread_create(&tid_3, NULL, thread_fun, "3") != 0) 56 err_exit("create thread 3"); 57 58 /* 主線程等待工作完成 */ 59 pthread_barrier_wait(&barrier); 60 printf("所有線程工作已完成...\n"); 61 62 sleep(1); 63 return 0; 64 }28行是線程自己要做的工作,62行的sleep(1)讓所有線程有足夠的時(shí)間把自己的返回值打印出來。編譯運(yùn)行:
可以看到,3個(gè)線程工作完成后才可以越過屏障打印返回值,第一個(gè)返回的是PTHREAD_BARRIER_SERIAL_THREAD,其他都是0。
這里有一點(diǎn)要注意:我們從運(yùn)行結(jié)果看出,主線程打印"所有線程工作已完成"之后,線程1,線程2還在運(yùn)行打印返回值。這個(gè)結(jié)果難免會誤解"主線程等待所有線程完成工作之后再向下執(zhí)行"。區(qū)分一點(diǎn)即可:等待只針對屏障之前的動作,越過屏障后,無論是主線程,還是子線程都會并發(fā)執(zhí)行,如果非要讓子線程完完全全執(zhí)行完,可以再加個(gè)屏障到線程函數(shù)末尾,相應(yīng)主線程也要加!
總結(jié)
以上是生活随笔為你收集整理的linux线程同步(5)-屏障的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IGMP技术总结
- 下一篇: linux线程同步(4)-自旋锁