條件變量是利用線程間共享的全局變量進行同步的一種機制。條件變量宏觀上類似if語句,符合條件就能執行某段程序,否則只能等待條件成立。
使用條件變量主要包括2個動作:一個等待使用資源的線程“等待條件變量被設置爲真”;另一個線程在使用完資源後“設置條件爲真”,這樣就可以保證線程間的同步了。那麼關鍵的問題來了,就是要保證條件變量能被正確地修改,條件變量應該得到特殊的保護。實際使用中其實仍然需要用到互斥鎖,互斥鎖充當了這樣一個保護者的角色。
條件變量的典型應用場景,是處理類似於如下特定情形的線程同步問題:
- 若干個線程在某個條件沒有滿足時不能繼續往下運行,紛紛調用pthread_cond_wait使自己在這個條件上陷入等待(休眠)。
- 當條件滿足後,提供任務的線程(即活躍着的)調用pthread_cond_broadcast(或pthread_cond_signal)通知(喚醒)剛纔那些等待在這個條件上的所有線程,讓它們繼續往下運行。
- 實際應用場景中,通常希望每調用一次pthread_cond_signal就喚醒一個等待線程。比如,某線程專門負責從網絡接收數據包,其他若干線程專門負責處理數據包。當沒有數據包時,處理線程全部調用pthread_cond_wait陷入等待。當一個數據包到達時,接收線程調用pthread_cond_signal喚醒一個處理線程來處理數據包。新的數據包到來時,接收線程再次調用pthread_cond_signal喚醒一個線程。
操作條件變量的函數
pthread_cond_init | 初始化條件變量 |
pthread_cond_wait | 基於條件變量阻塞,無條件等待 |
pthread_cond_timedwait | 阻塞直到指定事件發生,計時等待 |
pthread_cond_signal | 解除特定線程的阻塞,存在多個等待線程時按入隊順序激活其中一個 |
pthread_cond_broadcast | 解除所有線程的阻塞 |
pthread_cond_destroy | 清除條件變量 |
條件變量的初始化,也有2種:
- 靜態賦值法,將宏結構常量PTHREAD_COND_INITIALIZER賦予互斥鎖:pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
- 使用函數pthread_cond_init,其原型如下。其中cond_attr是條件變量的屬性,通常設置爲NULL。
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
等待條件成立有2個函數:pthread_cond_wait和pthread_cond_timedwait。
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timewait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);
上述2個函數用法類似,函數將阻塞直到條件變量獲得信號。區別是後者增添了一個超時abstime,如果在給定時限前條件仍未滿足,則返回ETIMEOUT,解除阻塞,結束等待。
C語言互斥鎖-條件變量的一個實例 ------ C語言互斥鎖---條件變量實現公共緩存區數據讀寫:
《注:以下程序實例引用自:http://blog.csdn.net/android_hasen/article/details/9735721。這個實例放到這裏說明條件變量的基本用法再合適不過了!!!》
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <error.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
char buffer[128];
int has_data=0;
pthread_mutex_t mutex;
pthread_cond_t cond;
pthread_cond_t cond2;
void read_buf(void)
{
do
{
pthread_mutex_lock(&mutex);//鎖定互斥鎖
if(has_data==0)
{
/*阻塞線程,等待另外一個線程發送信號,同時爲公共數據區解鎖*/
pthread_cond_wait(&cond,&mutex);
}
else if(has_data==1)
{
printf("the data : %s\n",buffer);
has_data=0;
pthread_cond_signal(&cond2);
}
pthread_mutex_unlock(&mutex);//打開互斥鎖
}while(strcmp(buffer,"#")!=0);
pthread_exit(NULL);
}
void write_buf(void)
{
char input[128];
do
{
pthread_mutex_lock(&mutex);
if(has_data==0)
{
memset(input,'\0',128);
printf("input data:\t");
scanf("%s",input);
sprintf(buffer,"%s",input);
has_data=1;
pthread_cond_signal(&cond);//條件改變,喚醒阻塞的線程
}
else if(has_data==1)
{
pthread_cond_wait(&cond2,&mutex);
}
pthread_mutex_unlock(&mutex);
}while(strcmp(input,"#")!=0);
pthread_exit(NULL);
}
int main(int argc,char **argv)
{
pthread_t id,id2;
pthread_cond_init(&cond,NULL);
pthread_cond_init(&cond2,NULL);
pthread_mutex_init(&mutex,NULL);
pthread_create(&id,NULL,(void *)read_buf,NULL);//返回值爲0,創建成功
pthread_create(&id2,NULL,(void *)write_buf,NULL);
pthread_join(id,NULL);
pthread_join(id2,NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}
運行結果: