互斥量,條件變數

2021-10-05 22:02:02 字數 2621 閱讀 6089

在程序喚醒與睡眠一文中,針對多程序的生產者-消費者問題,我們提出了基於訊號量的解決方案.該方案避免了程序在等待其要求的下一步執行條件時進入忙等待狀態.我們使用了三個訊號量,訊號量mutex用於保證生產者程序與消費者程序不會同時訪問緩衝區.訊號量empty用於保證當緩衝區滿是生產者被阻塞進入休眠狀態,當緩衝區不滿時其能夠被再次喚醒.訊號量full用於保證當緩衝區空時消費者被阻塞進入休眠狀態,當緩衝區不空時其將被生產者程序喚醒.

訊號量可以儲存當前計數值,down操作對當前計數值減1,up操作對當前計數值加1,訊號量也正是通過其當前計數值來判斷是否應當阻塞呼叫程序.如果當前訊號量取值為0,則down操作將阻塞當前呼叫程序.

我們能夠在不利用訊號量計數能力的條件下解決該問題呢?我們可以使用互斥量條件變數

基於互斥量與條件變數的解決方案

互斥量互斥量主要用於確保對程序對臨界區的互斥訪問.它有兩個狀態,鎖狀態與解鎖狀態.對應的,對互斥量的兩個可能操作為加鎖操作與解鎖操作.程序在準備進入臨界區時,將嘗試對當前互斥量加鎖,如果當前互斥量為鎖狀態,則呼叫程序將被阻塞.如果當前互斥量為解鎖狀態,則程序將進入臨界區,互斥量將被轉化為鎖狀態.在程序準備離開緩衝區時,應當將當前互斥量解鎖,並喚醒阻塞在該互斥量上的程序.如果多個程序阻塞在該互斥量上,則隨機選擇乙個程序喚醒.

在如何避免多程序(執行緒)因競爭條件引發的錯誤?一文中,我們提到,鎖變數(即此處的互斥量)實現的重點在於確保對鎖變數的加鎖操作是原子操作,對鎖變數的加鎖操作包括兩步:1.檢查當前鎖變數取值,2.加鎖.因此必須通過適當的方案保證對加鎖操作是原子性的.

條件變數

條件變數則用於在未達到下一步執行條件時阻塞呼叫程序.當下一條件滿足時,需要通知當前條件變數取消對呼叫程序的阻塞.在多程序協作程式中,當前程序的執行通常可能需要滿足一些特定條件,而該條件需要通過其他程序的執行來滿足.因此如果當前程序在呼叫時被條件變數阻塞,則在其他程序滿足該程序執行條件時,應當負責通知條件變數,取消對等待程序的阻塞.

在生產者-消費者問題中,生產者的執行需要保證當前緩衝區有空餘空間,而這一條件需要消費者程序來提供.因此,如果消費者程序的執行提供了緩衝區有空餘空間這一條件,則消費者程序應當通知條件變數,取消對生產者程序的阻塞.同樣的,消費者程序的執行需要保證當前緩衝區不為空,而這一條件則需要生產者程序來提供.當生產者程序的執行使得當前緩衝區不為空時,其需要通知條件變數,取消對消費者程序的阻塞.條件變數的阻塞與喚醒通常命名為wait()signal()

互斥量與條件變數

互斥量與條件變數通常是同時使用的.程序首先使用互斥量確保當前對臨界區的互斥訪問,隨後使用條件變數檢查是否滿足下一步執行條件.我們在喚醒與睡眠最後一段中提到,如果我們首先執行down(&mutex),再執行down(&empty),則可能使得生產者程序與消費者程序均阻塞,引發死鎖.回到當前例子中,如果程序在對互斥量加鎖後,被條件變數阻塞,那是否也會引發死鎖呢?確實會.為了避免死鎖,條件變數在阻塞當前呼叫程序前,必須對互斥量解鎖,以使得其他程序可以執行.因此wait操作通常接受兩個引數,乙個是條件變數,乙個是與其協作的互斥量.

關於條件變數,還有一點值得特別指出.不像訊號量可以駐留在記憶體中,如果我們協作程序對某一條件變數呼叫signal(),然而此時並沒有程序阻塞在該訊號量上,則當前程序將被忽略.因此,程式設計師在編寫程式時,一定要保證wait的呼叫在signal()之前.這個問題類似於我們在喚醒與睡眠中提到的,如果對程序的wakeup()操作呼叫發生在sleep()之前,則喚醒訊號將被忽略.

使用pthread執行緒庫實現多執行緒生產者與消費者

我們使用pthread多執行緒庫解決多執行緒生產者與消費者問題.

#include

#include

#define max 10000000000 

//需要生產的數量了

pthread_mutex_t the_mutex;

//互斥量

pthread_cond_t condc, condp;

//建立用於消費者與生產者的條件變數了

int buffer =0;

//生產者與消費者使用的緩衝區.

void

*producer

(void

*ptr)

pthread_exit(0

);}void

*consumer

(void

*ptr)

pthread_exit(0

);}int

main

(int argc,

char

** ar**)

注意到,在條件變數的操作位於臨界區當中,因此不會出現條件變數還未執行wait()操作便執行signal().例如,如果當前消費者判斷buffer ==0 ,則將執行wait()操作阻塞消費者程序,則這一過程中,其不會被生產者影響,因為它位於臨界區中.

互斥量和條件變數

一。互斥量和條件變數簡介 互斥量 mutex 從本質上說是一把鎖,在訪問共享資源前對互斥量進行加鎖,在訪問完成後釋放互斥量上的鎖。對互斥量進行加鎖以後,任何其他試圖再次對互斥鎖加鎖的執行緒將會阻塞直到當前執行緒釋放該互斥鎖。如果釋放互斥鎖時有多個執行緒阻塞,所有在該互斥鎖上的阻塞執行緒都會變成可執行...

互斥量(互斥鎖)與條件變數

使用pthread的互斥介面來保護資料,確保同一時間只有乙個執行緒訪問資料。互斥量從本質上來說是把鎖。條件變數是執行緒可用的另一種同步機制。條件變數給多個執行緒提供了乙個會和的場所。條件變數與互斥量一起使用時,允許執行緒以無競爭的方式等待特定的條件發生。條件本身是由互斥量保護的。我們使用pthrea...

C 封裝互斥量和條件變數

1 互斥量是保護臨界區的另一種方法,當執行執行緒在臨界區的執行時間很長時,那麼就最好使用互斥量了,否則會造成其他的執行緒將會在臨界區外忙等,浪費cpu時間 此時其他執行緒發現臨界區已經被互斥量鎖住,那麼它們將會阻塞 當互斥量被釋放時,有多個執行緒在阻塞,多個執行緒均會被喚醒,但是只有乙個執行緒可以獲...