??一.條件變量
? ? 條件變量是用來等待線程而不是上鎖的,條件變量通常和互斥鎖一起使用。條件變量之所以要和互斥鎖一起使用,主要是因為互斥鎖的一個明顯的特點就是它只有兩種狀態:鎖定和非鎖定,而條件變量可以通過允許線程阻塞和等待另一個線程發送信號來彌補互斥鎖的不足,所以互斥鎖和條件變量通常一起使用。
? ? 當條件滿足的時候,線程通常解鎖并等待該條件發生變化,一旦另一個線程修改了環境變量,就會通知相應的環境變量喚醒一個或者多個被這個條件變量阻塞的線程。這些被喚醒的線程將重新上鎖,并測試條件是否滿足。一般來說條件變量被用于線程間的同步;當條件不滿足的時候,允許其中的一個執行流掛起和等待。
條件變量中常用的API:
? ? ?1).條件變量類型為:pthread_cond_t ,類似互斥變量,條件變量的初始化有兩種方式:
? ? ? 靜態:pthread_cond_t mycon=PTHREAD_COND_INITIALIZER;
? ? ? 動態:通過調用pthread_cond_init函數,函數原型為:
- 靜態:pthread_cond_t?mycon=PTHREAD_COND_INITIALIZER;??
? ? ?cond:環境變量.
? ? ?attr:條件變量屬性.
? ? ?成功返回0,失敗返回錯誤碼.
? ? ?2).條件變量摧毀函數:pthread_cond_destroy(&mycond);
- int?pthread_cond_destroy(pthread_cond_t?*cond);??
? ? ?成功返回0,失敗返回錯誤碼.
? ? ?摧毀所指定的條件變量,同時將會釋放所給它分配的資源。調用該函數的進程也并不等待在參數所指定的條件變量上。
? ? ?3).條件變量等待函數。pthread_cond_wait(&mycond,&mylock);
? ? ?
- int?pthread_cond_timedwait(pthread_cond_t?*restrict?cond,??
- ???????????pthread_mutex_t?*restrict?mutex,??
- ???????????const?struct?timespec?*restrict?abstime);??
- ????int?pthread_cond_wait(pthread_cond_t?*restrict?cond,??
- ???????????pthread_mutex_t?*restrict?mutex);??
? ? cond:條件變量
? ? mutex:互斥鎖
?pthread_cond_wait和pthread_cond_timedwait的區別:
? ??pthread_cond_timedwait函數類型與函數pthread_cond_wait,區別在于,如果達到或是超過所引用的參數*abstime,它將結束并返回錯誤ETIME.
? ? timespec
- typedef?struct?timespec??
- ???{??
- ??????time_t?????tv_sec;??????
- ??????long?????tv_nsex;??????
- ???}timespec_t;??
? ? 當時間超過之前預設定的時會返回錯誤.
? ? 4).條件變量通知函數:pthread_cond_signal和pthread_cond_broadcast
- int?pthread_cond_broadcast(pthread_cond_t?*cond);??
- int?pthread_cond_signal(pthread_cond_t?*cond);??
pthread_cond_signal和pthread_cond_broadcast的區別:
? ? ? ?pthread_cond_signal:只喚醒一個在相同條件變量中阻塞的線程將會被喚醒
? ? ? ?pthread_cond_broadcast:喚醒等待隊列中的所有線程
二.一個關于互斥鎖和條件變量的栗子
? ?栗子:用互斥鎖和條件變量的概念實現一個簡單的生產者和消費者的模型。
?生產者和消費者模型:
? ? 1).滿足互斥與同步條件,用互斥鎖和條件變量實現
? ? 2).多個生產者和消費者:生產者和生產者屬于互斥關系;生產者和消費者屬于互斥和同步關系;消費者和消費者屬于競爭關系,需要互斥鎖
? ? 3).生產者和消費者模型中存在如下幾種關系和角色:3種關系,2種角色,1種交換媒介(一般是一段內存)
? ? 下例以單生產者和單消費者,交換媒介為鏈表實現的生產者消費者模型
? ? ?
- procon.c??
- ??
- #include<stdio.h>??
- #include<stdlib.h>??
- #include<assert.h>??
- #include<pthread.h>??
- ??
- typedef?struct?LinkNode??
- {??
- ????int?data;??
- ????struct?LinkNode?*next;??
- }Node;??
- ??
- pthread_mutex_t?mylock=PTHREAD_MUTEX_INITIALIZER;??
- pthread_cond_t?mycond=PTHREAD_COND_INITIALIZER;??
- ??
- Node?*CreatNode(int?data)??
- {??
- ????Node?*NewNode=(Node?*)malloc(sizeof(Node));??
- ????if(NULL?==?NewNode)??
- ????{??
- ????????perror("malloc");??
- ????????return?NULL;??
- ????}??
- ????NewNode->data=data;??
- ????NewNode->next=NULL;??
- ????return?NewNode;??
- }??
- ??
- void?InitLink(Node?**head)??
- {??
- ????*head=CreatNode(0);??
- }??
- ??
- int?IsEmpty(Node?*head)??
- {??
- ????assert(head);??
- ????if(head->next)??
- ????????return?0;??????
- ????else??
- ????????return?1;??????
- }??
- ??
- void?PushFront(Node?*head,int?data)??
- {??
- ????assert(head);??
- ????Node?*NewNode=CreatNode(data);??
- ????NewNode->next=head->next;??
- ????head->next=NewNode;??
- }??
- ??
- void?PopFront(Node?*head,int?*data)??
- {??
- ????assert(data);??
- ????assert(head);??
- ????if(IsEmpty(head))??
- ????{??
- ????????printf("empty?link\n");??
- ????????return?;??
- ????}??
- ????Node?*del=head->next;??
- ????*data=del->data;??
- ????head->next=del->next;??
- ????free(del);??
- ????del=NULL;??
- }??
- ??
- void?DisplayLink(Node?*head)??
- {??
- ????assert(head);??
- ????Node?*cur=head->next;??
- ????while(cur)??
- ????{??
- ????????printf("%d?",cur->data);??
- ????????cur=cur->next;??
- ????}??
- ????printf("\n");??
- }??
- ??
- void?DestroyLink(Node?*head)??
- {??
- ????int?data=0;??
- ????assert(head);??
- ????while(!IsEmpty(head))??
- ????{??
- ????????PopFront(head,&data);??
- ????}??
- ????free(head);??
- }??
- ??
- void?*product_run(void?*arg)??
- {??
- ????int?data=0;??
- ????Node?*head=(Node?*)arg;??
- ????while(1)??
- ????{??
- ????????usleep(100000);??
- ????????data=rand()%1000;??
- ????????pthread_mutex_lock(&mylock);??
- ????????PushFront(head,data);??
- ????????pthread_mutex_unlock(&mylock);??
- ????????pthread_cond_signal(&mycond);??
- ????????printf("product?is?done,data=%d\n",data);??
- ????}??
- }??
- ??
- void?*consumer_run(void?*arg)??
- {??
- ????int?data=0;??
- ????Node?*head=(Node?*)arg;??
- ????while(1)??
- ????{??
- ????????pthread_mutex_lock(&mylock);??
- ????????while(IsEmpty(head))??
- ????????{??
- ????????????pthread_cond_wait(&mycond,&mylock);??
- ????????}??
- ????????PopFront(head,&data);??
- ????????pthread_mutex_unlock(&mylock);??
- ????????printf("consumer?is?done,data=%d\n",data);??
- ????}??
- }??
- ??
- void?testprocon()??
- {??
- ????Node?*head=NULL;??
- ????InitLink(&head);??
- ????pthread_t?tid1;??
- ????pthread_t?tid2;??
- ????pthread_create(&tid1,NULL,product_run,(void?*)head);??
- ????pthread_create(&tid2,NULL,consumer_run,(void?*)head);??
- ??
- ????pthread_join(tid1,NULL);??
- ????pthread_join(tid2,NULL);??
- ????DestroyLink(head);??
- ????pthread_mutex_destroy(&mylock);??
- ????pthread_cond_destroy(&mycond);??
- ??
- }??
- int?main()??
- {??
- ????testprocon();??
- ????return?0;??
- }??
- ??
- Makefile??
- procon:procon.c??
- ????gcc?-o?$@?$^?-lpthread??
- .PHONY:clean??
- clean:??
- ????rm?-f?procon??
? ??
總結:
? ?條件變量用在某個線程需要在某種條件才去保護它將要操作的臨界區的情況下,從而避免了線程不斷輪詢檢查該條件是否成立而降低效率的情況,這是實現了效率提高。
? 希望對讀者有幫助吧~~~~
? ??