執行緒間的同步還有乙個情況:程序a 需要等待乙個條件成立,才執行,當條件不成立時就阻塞等待 ;程序b 需要設定條件,當條件成立時,喚醒程序a.這裡我們就可以用到條件變數。
條件變數變數也是出自posix執行緒標準,另一種執行緒同步機制,主要用來等待某個條件的發生,然後進行相應的操作,這樣可以消除多執行緒間的競爭。每個條件變數總是和乙個互斥量相關聯,條件本身是由互斥量保護的,執行緒在改變條件狀態之間必須要鎖住互斥量。互斥量是用於上鎖,條件變數用於等待。
1. 條件變數的初始化和銷毀
#include int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
pthread_cond_t cond = pthread_cond_initializer;
//成功返回0,失敗返回錯誤碼
condition variable 與mutex 有類似的初始化函式pthread_cond_init, 當attr 為null 就相當於pthread_cond_initializer
2. 條件變數的相關操作函式
#include 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);
int pthread_cond_broadcast(pthread_cond_t *cond);int pthread_cond_signal(pthread_cond_t *cond);
condtion variable 總是搭配mutex 使用,超時條件變數的作用是為了防止某個執行緒因為異常終止,沒有及時釋放鎖,超時會導致鎖因為超時而釋放。
3. 條件變數的使用例項
#include #include #include #include #include #include #include static int count = 0;
pthread_cond_t g_cond = pthread_cond_initializer;
pthread_mutex_t g_cond_lock = pthread_mutex_initializer;
void *notify_thx_func(void *arg)
}void *recv_thx_func(void *arg)
printf("i got the data ...\r\n");
count--;
pthread_mutex_unlock(&g_cond_lock);
}}int main(int argc, char **argv)
4. 關於虛假喚醒 (spurious wakeups)
互斥器和條件變數用法如下:
pthread_mutex_lock(&lock);
while (condition_is_false)
上面那個while能換成if嗎?答案是不能,否則會導致spurious wakeup虛假喚醒。因為不僅要在pthread_cond_wait前要檢查條件是否成立,在pthread_cond_wait之後也要檢查。因為pthread_cond_wait不僅能被pthread_cond_signal/pthread_cond_broadcast喚醒,而且還會被其它訊號喚醒,後者就是虛假喚醒。
考慮乙個生產者消費者佇列中的三個執行緒。
執行緒a正等待從執行緒安全的佇列中讀取乙個元素。
執行緒b向佇列中新增乙個元素。在對佇列解鎖後,但在發出條件訊號之前,發生了上下文切換。
執行緒c向佇列中新增乙個元素,並成功發出條件訊號。
執行緒a被喚醒,並處理了上面兩個元素。它接著等待被喚醒。
執行緒b恢復現場,並發出條件訊號。
這時執行緒a被喚醒,但立即又進入睡眠,因為隊列為空。
這個例子很好的解釋了虛假喚醒,雖然沒有什麼***,但是卻有可能浪費cpu時間。
既然你已經始終需要檢查謂詞在乙個迴圈,這沒有什麼區別。 如果基礎條件變數可以有其他型別的虛假喚醒。
linux的pthread_cond_wait是用futex系統呼叫,這個是慢速系統呼叫,看過apue知道任何慢速系統呼叫被訊號打斷的時候會返回 -1,並且把errno置為eintr,如果慢速系統呼叫的重啟功能被關閉,需要在呼叫該系統呼叫的地方手動重啟它,像下面這樣:
while (1)
但是futex不能這麼用,因為futex結束後到再次重啟這個過程有個時間窗,在這個視窗內可能發生了pthread_cond_signal/phread_cond_broadcast,如果發生這種情況,再進行pthread_cond_wait的時候就錯過了一次條件變數的變化,就會無限等待下去。但是如果不像上面那樣寫又無法重啟futex系統呼叫,咋整呢?這就回到了上面檢查布林條件的時候為什麼用while而不用if。用while不會因為虛假喚醒而錯過phread_cond_signal/pthread_cond_broadcast,而且在通過判斷while條件不成立檢測出此次喚醒為虛假喚醒並繼續呼叫futex繼續等待。
Linux 執行緒同步 條件變數
pthread cond signal 使在條件變數上等待的執行緒中的乙個執行緒重新開始。如果沒有等待的執行緒,則什麼也不做。如果有多個執行緒在等待該條件,只有乙個能重啟動,但不能指定哪乙個。pthread cond broadcast 重啟動等待該條件變數的所有執行緒。如果沒有等待的執行緒,則什麼...
Linux執行緒同步之條件變數
與互斥鎖不同,條件變數是用來等待而不是用來上鎖的。條件變數用來自動阻塞乙個執行緒,直到某特殊情況發生為止。通常條件變數和互斥鎖同時使用。條件變數使我們可以睡眠等待某種條件出現。條件變數是利用執行緒間共享的全域性變數進行同步的一種機制,主要包括兩個動作 乙個執行緒等待 條件變數的條件成立 而掛起 另乙...
Linux執行緒同步之 條件變數
條件變數是執行緒可用的另一種同步機制。條件變數給多執行緒提供了乙個會合的場所。它主要包括兩個動作 乙個執行緒等待 條件變數的條件成立 而掛起 另乙個執行緒使 條件成立 給出條件成立訊號 條件變數與互斥量一起使用時,允許執行緒以無競爭的方式等待特定的條件發生。條件變數本身是互斥量保護的。執行緒在改變條...