2008-09-16 67 views
41

使用pthread_cond_wait或使用信號量有什麼優點/缺點? 我等待這樣的狀態變化:pthread_cond_wait與信號量

pthread_mutex_lock(&cam->video_lock); 
while(cam->status == WAIT_DISPLAY) { 
    pthread_cond_wait(&cam->video_cond, &cam->video_lock); 
} 
pthread_mutex_unlock(&cam->video_lock); 

使用正確初始化旗語,我想我能做到這一點是這樣的:

while(cam->status == WAIT_DISPLAY) { 
    sem_wait(&some_semaphore); 
} 

什麼是每種方法的利弊?

+0

我剛剛意識到「正確初始化旗語」是不明確的。信號量是否設置爲1或0?我會說它應該被設置爲0.然後,信號量是否保護凸輪 - >狀態? – Blaisorblade 2014-06-01 22:45:33

+0

在其他答案中提到的第二個片段中,當互斥體未被釋放時,您的線程將被阻塞。所以你的`sem_wait`方法永遠不會返回,因爲沒有其他線程可以獲得互斥體並調用`sem_signal`。但是,如果我在`sem_wait`之前釋放互斥並在等待之後再次請求它,我不會發生什麼。我知道這些步驟不是原子的,那麼會發生什麼? – sevenkplus 2016-10-03 15:31:54

回答

58

儘管信號量還有其他用途,但它適用於生產者 - 消費者模型。您的程序邏輯負責確保爲等待次數提供適當的帖子數量。如果你發佈一個信號而沒有人等待,那麼當他們等待時,他們立即繼續。如果您的問題可以用信號量的計數值來解釋,那麼使用信號量應該很容易解決。

條件變量在某些方面有點寬容。例如,您可以使用cond_broadcast喚醒所有服務員,而製片人不知道有多少人。如果你沒有人在等待它,cond_signal condvar然後沒有反應。如果你不知道是否有興趣的聽衆,這很好。這也是爲什麼聆聽者應該總是在等待之前檢查互斥狀態 - 如果他們不這樣,他們就會錯過一個信號,直到下一個(可能永遠不會)醒來。

所以一個條件變量適用於通知感興趣的各方狀態已經改變:你獲得互斥量,改變狀態,信號(或廣播)condvar並釋放互斥量。如果這描述你的問題,你在condvar領土。如果不同的聽衆對不同的狀態感興趣,你可以直接播放,然後每個人都會醒來,找出他們是否已經找到了他們想要的狀態,如果不再等待。

用互斥量和信號量來嘗試這種事情確實非常困難。問題出現在你想要獲取互斥鎖時,檢查一些狀態,然後等待信號量發生變化。除非你可以自動釋放互斥量並等待信號量(在pthread中你不能),否則最終等待信號量同時持有互斥量。這會阻止互斥體,這意味着其他人無法將其用於執行您關心的更改。所以你會被誘惑添加另一個互斥體,這取決於你的具體要求。也許是另一個信號量。結果通常是不正確的代碼,有害的競態條件。

條件變量可以避免這個問題,因爲調用cond_wait會自動釋放互斥鎖,釋放它以供其他人使用。在cond_wait返回之前,互斥體會重新獲得。

IIRC有可能僅使用信號量來實現一種condvar,但是如果您要實現與condvar一起使用的互斥鎖需要使用trylock,那麼它是一個嚴重的頭部劃傷,並且定時等待。不建議。所以不要認爲你可以用condvar做什麼都可以用信號量來完成。此外,當然互斥體可以有很好的信號量缺乏行爲,主要是避免優先級倒置。

0

在你的第二個片段中,你獲得了多次鎖定,永遠不會釋放它。

一般來說,你所說的狀態可以完全用信號量表示,那麼你可以使用它。鎖結構體積較小,並且需要較少的原子操作來檢查/設置/釋放。否則,如果狀態複雜,並且代碼的不同部分在相同變量的不同條件下等待(例如,此處需要x < 10;那麼您希望y> x),請使用cond_wait。否則,請使用cond_wait。

+0

第二個片段是正確的 - 喚醒總是由某個人發出信號燈引起的。 – Blaisorblade 2009-01-12 09:04:46

+0

@Blaisorblade,醒來是正確的,狀態檢查是否定的,因爲它沒有被保護。 – 2014-05-28 03:59:29

19

條件允許你做一些信號量不會的事情。

例如,假設您有一些需要互斥體的代碼,稱爲m。然而,它需要等到其他線程完成任務後,纔會等待一個名爲s的信號量。現在任何需要m的線程都會被阻止運行,即使線程m正在等待s。這些情況可以使用條件來解決。當你等待一個條件時,當前持有的互斥鎖被釋放,所以其他線程可以獲得互斥鎖。回到我們的例子,假設使用條件c而不是s。我們的線程現在獲取m,然後有條件地等待c。這會釋放m以便其他線程可以繼續。當c變得可用時,m被重新獲得,並且我們的原始線程可以繼續愉快地沿着它的方式。

條件變量還允許您讓全部線程等待條件變量通過pthread_cond_broadcast繼續。此外,它還允許您執行定時等待,因此您不會永遠等待。

當然,有時候你不需要條件變量,所以根據你的要求,其中一個可能會更好。

4

第二個片段是活潑的,不要這樣做。

其他答案對相對優點有很好的討論;我只是補充說明pthread_cond_broadcast是條件變量的明顯優勢。

除此之外,我只是更習慣於爲變量指定條件,因爲它們是您在Java中使用的變量,即使它們在檢查共享標誌時幫助您避免競爭。

確實,在第二個片段中,您沒有任何鎖定來保護cam-> status的讀取,因此可以通過數據競爭來訪問它。在這個特例中,大多數平臺都可以讓你擺脫這種困境,但是這種平臺具有未定義的語義,POSIX和下一個C/C++標準的內存模型。

事實上,如果另一個線程分配一個新的凸輪結構並覆蓋凸輪,則可能存在真實的競爭條件;等待的線程可能會看到'cam'指針的更新,而沒有看到cam-> status的初始化。事實上,在這種情況下和總體上,第二個片段正在尋求麻煩。

http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/