Linux 多執行緒程式設計(三)

2021-05-27 08:34:27 字數 4332 閱讀 6519

繼續昨天的執行緒同步,條件變數(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...