OS / Linux / pthread_cond_wait 为什么需要传递 mutex 参数?
栗子:
mutex.lock();while (判斷“條件”是否成立) {pthread_cond_wait 等待 }mutext.unlock();條件變量這個(gè)互斥鎖,不是用來保護(hù)條件變量的內(nèi)部狀態(tài)。而是用來保護(hù)外部“條件”(就是那個(gè) while 循環(huán)中的判斷)。假如條件變量的內(nèi)部狀態(tài)需要鎖定,完全可以在內(nèi)部實(shí)現(xiàn)中維護(hù)一個(gè)鎖,沒有必要從外部傳進(jìn)來。
用于判斷是否等待的“條件”,通常就是線程之間共享的某個(gè)變量值。A 線程判斷“條件”等待,會(huì)讀取共享變量。B 線程讓“條件”滿足,會(huì)修改變量。這個(gè)鎖,就是保護(hù)線程間的共享變量(“條件”),讓“條件”不會(huì)一邊修改,一邊讀取。
這把鎖還有個(gè)額外的作用。wait 函數(shù)會(huì)阻塞,將線程 A 放到阻塞隊(duì)列中。wait 函數(shù)放在鎖的 lock,unlock 內(nèi)部,也保證了線程還沒有真正放到阻塞隊(duì)列時(shí),線程 B 不能修改“條件”后進(jìn)行喚醒。這段話應(yīng)該暫時(shí)讀不懂,可回頭再看,先放在這里,不然描述就不夠準(zhǔn)確。
不同的應(yīng)用會(huì)有不同的“條件”,在實(shí)現(xiàn)條件變量這個(gè)庫時(shí),是沒有辦法預(yù)先知道這個(gè)“條件”究竟是什么。因此要保護(hù)“條件”,就只能讓用戶自己在庫外部分配鎖。
弄清了這個(gè)互斥鎖究竟在保護(hù)什么。這時(shí)我們才能進(jìn)一步討論 pthread_cond_wait 為什么要傳入這個(gè)鎖呢?這點(diǎn)就跟 wait 的實(shí)現(xiàn)有關(guān)。
先來看等待線程 A 的寫法。
mutex.lock();while (判斷“條件”是否成立) {pthread_cond_wait 等待 }mutext.unlock();判斷“條件”是否成立,在 lock, unlock 之間受到保護(hù)。pthread_cond_wait 可能會(huì)阻塞,假如真的阻塞,mutex 這鎖就一直不能被釋放了。因此在 pthread_cond_wait 的實(shí)現(xiàn)內(nèi)部,在阻塞之前,必須先將鎖釋放。在喚醒的時(shí)候,再重新獲取鎖。
將 pthread_cond_wait 展開,內(nèi)部實(shí)現(xiàn)中,會(huì)有下面的過程。
做一些其它事情 mutext.unlock() 阻塞中... 喚醒 mutext.lock()假如在線程 A 中完全展開 pthread_cond_wait。
mutex.lock();while (判斷“條件”是否成立) {做一些其它事情mutext.unlock()阻塞喚醒mutext.lock() }mutext.unlock();可以看到,判斷“條件” 一直在 mutext 的 lock, unlock 之間,受到保護(hù)。
來到這里,我們總結(jié)一下。
注意上面第 2 點(diǎn)中,“適當(dāng)時(shí)機(jī)”這個(gè)詞。假如不將這個(gè)鎖傳入 pthread_cond_wait,讓用戶自己在阻塞前先釋放鎖,是沒有辦法做到適當(dāng)時(shí)機(jī)的。阻塞隊(duì)列在條件變量庫內(nèi)部維護(hù),只有條件變量庫內(nèi)部才能控制這個(gè)時(shí)機(jī)。
wait 會(huì)阻塞,將線程 A 放到阻塞隊(duì)列中。在線程還沒有真正放到阻塞隊(duì)列時(shí),需要一直上鎖。不然另一線程 B 修改“條件”后進(jìn)行喚醒,這個(gè)線程 A 還沒有在阻塞隊(duì)列中,就不能被喚醒了。因而這把保護(hù)外部判斷“條件”的鎖,需要傳入到 wait 函數(shù)中。等將線程真正放到阻塞隊(duì)列后才能解鎖,之后線程被喚醒后再重新獲取。
線程 A 的 pthread_cond_wait 需要傳入 mutext,并且 pthread_cond_wait 一定要在 lock 和 unlock 之間。
至于線程 B, 用于修改“條件”。修改“條件” 也必須在 lock 和 unlock 之間,受互斥鎖保護(hù)。至于 pthread_cond_signal 是否在 lock 和 unlock 之間,其實(shí)是沒有關(guān)系的。但 pthread_cond_signal 必須在修改“條件”之后,不然可能 A 線程被喚醒后,條件不滿足繼續(xù)等待,這個(gè)喚醒信號(hào)就丟失了。
mutext.lock() 修改”條件“ pthread_cond_signal 喚醒 mutext.unlock()也可以將 pthread_cond_signal 移到 unlock 外部。
mutext.lock() 修改”條件“ mutext.unlock() pthread_cond_signal 喚醒條件變量等待時(shí),那個(gè) wait 的判斷,需要使用 while 循環(huán),而不是 if,是防止虛假喚醒。就不再一一分析了。
?
作者:黃兢成
鏈接:https://www.zhihu.com/question/24116967/answer/676751734
來源:知乎
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
?
(SAW:Game Over!)
總結(jié)
以上是生活随笔為你收集整理的OS / Linux / pthread_cond_wait 为什么需要传递 mutex 参数?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OS / 进程启动过程
- 下一篇: Qt / Moc 和信号 - 槽解析