繼續昨天的執行緒同步,條件變數(condition variables)是用於執行緒間,通訊共享資料狀態改變的機制。
簡介條件變數的建立和銷毀
等待條件變數
喚醒等待條件變數的執行緒
簡介 當執行緒互斥地訪問一些共享的狀態時,往往會有些執行緒需要等到這些狀態改變後才應該繼續執行。如:有乙個共享的佇列,乙個執行緒往佇列裡面插入資料,另乙個執行緒從佇列中取資料,當隊列為空的時候,後者應該等待佇列裡面有值才能取資料。而共享資料(佇列)應該用mutex來保護,為了檢查共享資料的狀態(佇列是否為空),執行緒必須先鎖定mutex,然後檢查,最後解鎖mutex。
問題出來了:當另外乙個執行緒b鎖定mutex後,往佇列裡面插入了乙個值,b並不知道a在等著它往佇列裡面放入乙個值。執行緒a(等待狀態改變)一直在執行,執行緒a可能已經檢查過佇列是空的,並不知道佇列裡已經有值了,所以一直阻塞著自己。為了解決這樣的問題引入了條件變數機制。執行緒a等待於乙個條件變數,當執行緒b插入了乙個值後,signal或broadcast這個條件變數,通知執行緒a狀態已改變,a發現條件變數被signaled 了,就繼續執行。就這樣,當乙個執行緒改變共享資料狀態後,可以及時通知那些等待於該狀態的執行緒。圖示下:
中間的矩形代表條件變數,當執行緒線位於矩形內,表示執行緒等待該條件變數。位於中心線下下方,則表示signal了該條件變數。處於低谷電平的屬於等待狀態,高電平的屬於執行狀態
開始執行緒1 signal 了條件變數,由於沒有其他執行緒等待於該條件變數,所以沒什麼效果。然後,執行緒1和執行緒2先後等待該條件變數,過了一會,執行緒3 signal了條件變數,執行緒3的訊號解除了執行緒1的阻塞。然後,執行緒3等待該條件變數。最後執行緒1 broadcast了該條件變數,同時解除了等待於條件變數的執行緒1和執行緒2。???
條件變數的建立和銷毀
pthread_cond_t cond = pthread_cond_initializer;
int pthread_cond_init(pthread_cond_t* cond, pthread_condattr_t* condattr);
int pthread_cond_destroy(pthread_cond_t* cond);
和互斥量一樣,可以動態建立和靜態建立。
靜態建立:條件變數宣告為extern或static變數時。
例程:#include
#include "error.h"
typedef struct my_struct_tag my_struct_t;
my_struct_t data = my_struct_t;
int main()
等待條件變數
int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex);
int pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, struct timespec* expiration);
條件變數與互斥量一起使用,呼叫pthread_cond_wait或pthread_cond_timedwait時,記得在前面鎖定mutex,盡可能多的判斷判定條件。上面提到的兩個等待條件變數的函式,顯示解鎖mutex,然後阻塞執行緒等待狀態改變,等待的條件變數 signaled後,鎖定mutex,返回。記著,這兩個函式返回時,mutex一定是鎖定的。
多個條件變數可以共享乙個互斥變數,相反則不成立。
例程:
#include
#include
#include "error.h"
#include
typedef struct my_struct_tag
my_struct_t;
my_struct_t data = ;
int hibernation = 1;
void* wait_thread(void* arg)
int main(int argc, char* argv)
if(data.value != 0)
printf("condition wa signaled!\n");
status = pthread_mutex_unlock(&data.mutex);
if(status != 0)
error_abort(status, "unlock mutex"); }
喚醒等待條件變數的執行緒
int pthread_cond_signal(pthread_cond_t* cond);
int pthread_cond_broadcast(pthread_cond_t* cond);
一但有執行緒由於某些判定條件(predicate)沒滿足,等待條件變數。我們就有必要當條件滿足時,傳送訊號去喚醒這些執行緒。
注意:broadcast通常很容易被認為是signal的通用版,其實不能這樣理解,準確一點應該說,signal是 broadcast的優化版。具體區別不大,但signal效率較broadcast高些。但你不確信有幾個執行緒等待條件變數時用 broadcast(when in doubt, broadcast!)。
例程:
#include "error.h"
#include
#include
#include
#include
typedef struct alarm_tag
alarm_t;
pthread_mutex_t alarm_mutex = pthread_mutex_initializer;
pthread_cond_t alarm_cond = pthread_cond_initializer;
alarm_t* alarm_list = null;
time_t current_alarm = 0;
/*** alarm_mutex need to be locked
*/void alarm_insert(alarm_t* alarm)
last = &next->link;
next = next->link;
}if(next == null)
/*for test: output the list*/
printf("[list: ");
for(next = alarm_list; next != null; next = next->link)
printf("]\n");
if(current_alarm ==0 || alarm->time < current_alarm)
}void* alarm_thread(void* arg)
alarm = alarm_list;
alarm_list = alarm->link;
now = time(null);
expired = 0;
if(alarm->time > now)
}if(!expired)
alarm_insert(alarm);
}else
expired = 1;
if(expired)
status = pthread_mutex_unlock(&alarm_mutex);
if(status != 0)
error_abort(status, "unlock mutex");
}return 0;
}int main()
status = pthread_mutex_lock(&alarm_mutex);
if(status != 0)
error_abort(status, "pthread mutex locking..");
alarm->time = time(null) + alarm->seconds;
/* insert into list*/
alarm_insert(alarm);
status = pthread_mutex_unlock(&alarm_mutex);
if(status != 0)
error_abort(status, "pthread mutex unlocking...");
}return 0;
}
Linux 多執行緒程式設計(三)
繼續昨天的執行緒同步,條件變數 condition variables 是用於執行緒間,通訊共享資料狀態改變的機制。簡介 條件變數的建立和銷毀 等待條件變數 喚醒等待條件變數的執行緒 簡介 當執行緒互斥地訪問一些共享的狀態時,往往會有些執行緒需要等到這些狀態改變後才應該繼續執行。如 有乙個共享的佇列...
linux多執行緒程式設計小結 三
第二節 計時等待 int pthread cond timewait pthread cond t cond,pthread mutex mutex,const timespec abstime 啟用乙個等待該條件的執行緒 存在多個等待執行緒時按入隊順序啟用其中乙個 int pthread cond...
多執行緒程式設計 三
放入資料 獲取資料 arrayblockingqueu 和 linkedblockingqueue arrayblockingqueu 是用陣列實現的有界阻塞佇列,並按照先進先出 fifo 的原則對元素進行排序。第乙個引數是容量 第二個引數是是否要保證執行緒的公平地訪問佇列 預設是false arr...