一、什么是條件變量
與互斥鎖不同,條件變量是用來等待而不是用來上鎖的。條件變量用來自動阻塞一個線程,直到某特殊情況發生為止。通常條件變量和互斥鎖同時使用。
條件變量使我們可以睡眠等待某種條件出現。條件變量是利用線程間共享的全局變量進行同步的一種機制,主要包括兩個動作:一個線程等待"條件變量的條件成立"而掛起;另一個線程使"條件成立"(給出條件成立信號)。
條
件的檢測是在互斥鎖的保護下進行的。如果一個條件為假,一個線程自動阻塞,并釋放等待狀態改變的互斥鎖。如果另一個線程改變了條件,它發信號給關聯的條件
變量,喚醒一個或多個等待它的線程,重新獲得互斥鎖,重新評價條件。如果兩進程共享可讀寫的內存,條件變量可以被用來實現這兩進程間的線程同步。
使用條件變量之前要先進行初始化。可以在單個語句中生成和初始化一個條件變量如:
pthread_cond_t my_condition=PTHREAD_COND_INITIALIZER;(用于進程間線程的通信)。
也可以利用函數pthread_cond_init動態初始化。
二、條件變量函數
1.
名稱: |
pthread_cond_init |
目標: |
條件變量初始化 |
頭文件: |
#include < pthread.h> |
函數原形: |
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); |
參數: |
cptr 條件變量
attr 條件變量屬性 |
返回值: |
成功返回0,出錯返回錯誤編號。 |
pthread_cond_init函數可以用來初始化一個條件變量。他使用變量attr所指定的屬性來初始化一個條件變量,如果參數attr為空,那么它將使用缺省的屬性來設置所指定的條件變量。
2.
名稱: |
pthread_cond_destroy |
目標: |
條件變量摧毀 |
頭文件: |
#include < pthread.h> |
函數原形: |
int pthread_cond_destroy(pthread_cond_t *cond); |
參數: |
cptr 條件變量 |
返回值: |
成功返回0,出錯返回錯誤編號。 |
pthread_cond_destroy函數可以用來摧毀所指定的條件變量,同時將會釋放所給它分配的資源。調用該函數的進程也并不要求等待在參數所指定的條件變量上。
3.
名稱: |
pthread_cond_wait/pthread_cond_timedwait |
目標: |
條件變量等待 |
頭文件: |
#include < pthread.h> |
函數原形: |
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t mytex,const struct timespec *abstime); |
參數: |
cond 條件變量
mutex 互斥鎖 |
返回值: |
成功返回0,出錯返回錯誤編號。 |
第一個參數*cond是指向一個條件變量的指針。第二個參數*mutex則是對相關的互斥鎖的指針。函數pthread_cond_timedwait函數類型與函數pthread_cond_wait,區別在于,如果達到或是超過所引用的參數*abstime,它將結束并返回錯誤ETIME.pthread_cond_timedwait函數的參數*abstime指向一個timespec結構。該結構如下:
typedef struct timespec{
time_t tv_sec;
long tv_nsex;
}timespec_t;
3.
名稱: |
pthread_cond_signal/pthread_cond_broadcast |
目標: |
條件變量通知 |
頭文件: |
#include < pthread.h> |
函數原形: |
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond); |
參數: |
cond 條件變量 |
返回值: |
成功返回0,出錯返回錯誤編號。 |
參數*cond是對類型為pthread_cond_t 的一個條件變量的指針。當調用pthread_cond_signal時一個在相同條件變量上阻塞的線程將被解鎖。如果同時有多個線程阻塞,則由調度策略確定接收通知的線程。如果調用pthread_cond_broadcast,則將通知阻塞在這個條件變量上的所有線程。一旦被喚醒,線程仍然會要求互斥鎖。如果當前沒有線程等待通知,則上面兩種調用實際上成為一個空操作。如果參數*cond指向非法地址,則返回值EINVAL。
下面是一個簡單的例子,我們可以從程序的運行來了解條件變量的作用。
#include <pthread.h> #include <stdio.h> #include <stdlib.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;/*初始化互斥鎖*/ pthread_cond_t cond = PTHREAD_COND_INITIALIZER;/*初始化條件變量*/
void *thread1(void *); void *thread2(void *);
int i=1; int main(void) { pthread_t t_a; pthread_t t_b;
pthread_create(&t_a,NULL,thread2,(void *)NULL);/*創建進程t_a*/ pthread_create(&t_b,NULL,thread1,(void *)NULL); /*創建進程t_b*/ pthread_join(t_b, NULL);/*等待進程t_b結束*/ pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cond); exit(0); }
void *thread1(void *junk) { for(i=1;i<=9;i++) { pthread_mutex_lock(&mutex);/*鎖住互斥量*/ if(i%3==0) pthread_cond_signal(&cond);/*條件改變,發送信號,通知t_b進程*/ else printf("thead1:%d\n",i); pthread_mutex_unlock(&mutex);/*解鎖互斥量*/
sleep(1); }
}
void *thread2(void *junk) { while(i<9) { pthread_mutex_lock(&mutex);
if(i%3!=0) pthread_cond_wait(&cond,&mutex);/*等待*/ printf("thread2:%d\n",i); pthread_mutex_unlock(&mutex);
sleep(1); }
} |
程序創建了2個新線程使他們同步運行,實現進程t_b打印20以內3的倍數,t_a打印其他的數,程序開始線程t_b不滿足條件等待,線程t_a運行使a循環加1并打印。直到i為3的倍數時,線程t_a發送信號通知進程t_b,這時t_b滿足條件,打印i值。
下面是運行結果:
#cc –lpthread –o cond cond.c
#./cond
thread1:1
thread1:2
thread2:3
thread1:4
thread1:5
thread2:6
thread1:7
thread1:8
thread2:9