一文搞懂多線(xiàn)程中各個(gè)難點(diǎn)
6.9讀寫(xiě)鎖
6.9.1什么是讀寫(xiě)鎖?
大部分情況下,對(duì)于共享變量的訪問(wèn)特點(diǎn):只是讀取共享變量的值,而不是修改,只有在少數(shù)情況下,才會(huì)真正的修改共享變量的值。
在這種情況下,讀請(qǐng)求之間是同步的,它們之間的并發(fā)訪問(wèn)是安全的。然而寫(xiě)請(qǐng)求必須鎖住讀請(qǐng)求和其它寫(xiě)請(qǐng)求。
即讀線(xiàn)程可多個(gè)同時(shí)讀,而寫(xiě)線(xiàn)程只允許同一時(shí)間內(nèi)一個(gè)線(xiàn)程去寫(xiě)。
6.9.2讀寫(xiě)鎖接口
#include
讀寫(xiě)鎖的默認(rèn)屬性:
對(duì)于調(diào)用pthread_rwlock_init初始化的讀寫(xiě)鎖,在不需要讀寫(xiě)鎖的時(shí)候,需要調(diào)用pthread_rwlock_destroy銷(xiāo)毀。
6.9.3讀者加鎖
#include
最大的好處就是,允許多個(gè)線(xiàn)程以只讀加鎖的方式獲取到讀寫(xiě)鎖;
本質(zhì)上,讀寫(xiě)鎖的內(nèi)部維護(hù)了一個(gè)引用計(jì)數(shù),每當(dāng)線(xiàn)程以讀方式獲取讀寫(xiě)鎖時(shí),該引用計(jì)數(shù)+1;
當(dāng)釋放以讀加鎖的方式的讀寫(xiě)鎖時(shí),會(huì)先對(duì)引用計(jì)數(shù)進(jìn)行-1,直到引用計(jì)數(shù)的值為0的時(shí)候,才真正釋放了這把讀寫(xiě)鎖。
6.9.4寫(xiě)者加鎖
#include
寫(xiě)鎖用的是獨(dú)占模式,如果當(dāng)前讀寫(xiě)鎖被某寫(xiě)線(xiàn)程占用著,則不允許任何讀鎖通過(guò)請(qǐng)求,也不允許任何寫(xiě)鎖請(qǐng)求通過(guò),讀鎖請(qǐng)求和寫(xiě)鎖請(qǐng)求都要陷入阻塞,直到線(xiàn)程釋放寫(xiě)鎖。
6.9.5 解鎖
#include
不論是讀者加鎖還是寫(xiě)者加鎖,都采用該接口進(jìn)行解釋。
讀者解鎖,只有當(dāng)引用計(jì)數(shù)為0的時(shí)候,才真正釋放了讀寫(xiě)鎖。
6.9.6讀寫(xiě)鎖的競(jìng)爭(zhēng)策略
對(duì)于讀寫(xiě)鎖而言,目前有兩種策略,讀者優(yōu)先和攜著優(yōu)先;
讀寫(xiě)鎖的類(lèi)型有如下幾種:
PTHREAD_RWLOCK_PREFER_READER_NP, //讀者優(yōu)先
PTHREAD_RWLOCK_PREFER_WRITER_NP, //很唬人, 但是也是讀者優(yōu)先
PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, //寫(xiě)者優(yōu)先
PTHREAD_RWLOCK_DEFAULT_NP = PTHREAD_RWLOCK_PREFER_READER_NP
讀者優(yōu)先:讀鎖來(lái)請(qǐng)求可以立即響應(yīng),只要有一個(gè)讀鎖沒(méi)完成,那么寫(xiě)鎖就無(wú)法寫(xiě)。這種策略是不公平的,極端情況下,寫(xiě)現(xiàn)場(chǎng)很可能被餓死,即線(xiàn)程總是拿不到鎖資源。
寫(xiě)者優(yōu)先:只要線(xiàn)程申請(qǐng)了寫(xiě)鎖,那么在寫(xiě)鎖后面到來(lái)的讀鎖請(qǐng)求就會(huì)統(tǒng)統(tǒng)被阻塞,不能先于寫(xiě)鎖拿到鎖。
讀寫(xiě)鎖實(shí)現(xiàn)中的變量及含義
對(duì)于讀請(qǐng)求而言:如果
1. 無(wú)線(xiàn)程持有寫(xiě)鎖,即_writer = 0.
2. 采用讀者優(yōu)先策略或者當(dāng)前沒(méi)有寫(xiě)鎖申請(qǐng)請(qǐng)求,即 _nr_writers_queue = 0
3. 當(dāng)滿(mǎn)足這兩個(gè)條件時(shí),讀鎖請(qǐng)求立即獲得讀鎖,返回之前執(zhí)行_nr_readers++,表示多了一個(gè)線(xiàn)程正在讀
4. 不滿(mǎn)足這兩個(gè)條件時(shí),執(zhí)行_nr_readers_queued++,表示增加了一個(gè)讀鎖等待者,然后調(diào)用futex,陷入阻塞。醒來(lái)之后,執(zhí)行_nr_readers_queued- -,再次判斷是否滿(mǎn)足條件1,2
對(duì)于寫(xiě)請(qǐng)求而言:如果
1. 無(wú)線(xiàn)程持有寫(xiě)鎖,即_writer = 0.
2. 沒(méi)有線(xiàn)程持有讀鎖,即_nr_readers = 0.
3. 如果上述條件滿(mǎn)足,就會(huì)立即拿到鎖,將_writer 置為當(dāng)前線(xiàn)程的ID
4. 如果不滿(mǎn)足,則執(zhí)行_nr_writers_queue++, 表示增加了一個(gè)寫(xiě)鎖等待者線(xiàn)程,然后執(zhí)行futex陷入等待。醒來(lái)后,先執(zhí)行_nr_writers_queue- -,再繼續(xù)判斷條件1,2
對(duì)于解鎖,如果當(dāng)前是寫(xiě)鎖:
1. 執(zhí)行_writer = 0.,表示釋放寫(xiě)鎖。
2. 根據(jù)_nr_writers_queue判斷有沒(méi)有寫(xiě)鎖,如果有則喚醒一個(gè)寫(xiě)鎖,如果沒(méi)有寫(xiě)鎖等待者,則喚醒所有的讀鎖等待者。
對(duì)于解鎖,如果當(dāng)前是讀鎖:
1. 執(zhí)行_nr_readers- -,表示讀鎖占有者少了一個(gè)。
2. 判斷_nr_readers是否等于0,是的話(huà)則表示當(dāng)前線(xiàn)程是最后一個(gè)讀鎖占有者,需要喚醒寫(xiě)鎖等待者或讀鎖等待者
3. 根據(jù)_nr_writers_queue判斷是否存在寫(xiě)鎖等待者,若有,則喚醒一個(gè)寫(xiě)鎖等待線(xiàn)程
4. 如果沒(méi)有寫(xiě)鎖等待者,判斷是否存在讀鎖等待者,若有,則喚醒全部的讀鎖等待者
讀寫(xiě)鎖很容易造成,讀者餓死或者寫(xiě)者餓死。
也可以設(shè)計(jì)公平的讀寫(xiě)鎖。
代碼:
#include
上述代碼很容易觸發(fā)線(xiàn)程餓死。
讀餓死或者寫(xiě)?zhàn)I死。
7.線(xiàn)程間同步7.1為什么需要線(xiàn)程同步?
線(xiàn)程同步是為了對(duì)臨界資源訪問(wèn)的合理性。
例如:
就像工廠里生產(chǎn)車(chē)間沒(méi)有原料了, 所有生產(chǎn)車(chē)間都停工了, 工人們都在車(chē)間睡覺(jué)。突然進(jìn)來(lái)一批原料, 如果原料充足, 你會(huì)發(fā)廣播給所有車(chē)間, 原料來(lái)了, 快來(lái)開(kāi)工吧。如果進(jìn)來(lái)的原料很少, 只夠一個(gè)車(chē)間開(kāi)工的, 你可能只會(huì)通知一個(gè)車(chē)間開(kāi)工。
7.2如何做到線(xiàn)程間同步?
條件等待是線(xiàn)程間同步的另一種方法。
如果條件不滿(mǎn)足, 它能做的事情就是等待, 等到條件滿(mǎn)足為止。通常條件的達(dá)成, 很可能取決于另一個(gè)線(xiàn)程, 比如生產(chǎn)者-消費(fèi)者模型。當(dāng)另外一個(gè)線(xiàn)程發(fā)現(xiàn)條件符合的時(shí)候, 它會(huì)選擇一個(gè)時(shí)機(jī)去通知等待在這個(gè)條件上的線(xiàn)程。有兩種可能性, 一種是喚醒一個(gè)線(xiàn)程, 一種是廣播, 喚醒其他線(xiàn)程。
則在這個(gè)情況下,需要做到:
1、線(xiàn)程在條件不滿(mǎn)足的情況下, 主動(dòng)讓出互斥量, 讓其他線(xiàn)程去折騰, 線(xiàn)程在此處等待, 等待條件的滿(mǎn)足;
2、一旦條件滿(mǎn)足, 線(xiàn)程就可以立刻被喚醒。
3、線(xiàn)程之所以可以安心等待, 依賴(lài)的是其他線(xiàn)程的協(xié)作, 它確信會(huì)有一個(gè)線(xiàn)程在發(fā)現(xiàn)條件滿(mǎn)足以后, 將向它發(fā)送信號(hào), 并且讓出互斥量。
7.3條件變量
本質(zhì)上是PCB等待隊(duì)列 + 等待接口 + 喚醒接口。
7.3.1條件變量的初始化
靜態(tài)初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
動(dòng)態(tài)初始化
pthread_cond_init(pthread_cond_t *cond,const pthread_condattr_t *attr);
7.3.2條件變量的等待
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
int pthread_cond_timedwait(pthread_cond_t *restrict conpthread_mutex_t *restrict mutex,const struct timespec *restrict abstime);
為什么這兩個(gè)接口中有互斥鎖?
條件不會(huì)無(wú)緣無(wú)故地突然變得滿(mǎn)足了, 必然會(huì)牽扯到共享數(shù)據(jù)的變化。所以一定要有互斥鎖來(lái)保護(hù)。沒(méi)有互斥鎖, 就無(wú)法安全地獲取和修改共享數(shù)據(jù)。
同步并沒(méi)有保證互斥,而保證互斥是使用到了互斥鎖。
pthread_mutex_lock(&m)
while(condition_is_false)
{
pthread_mutex_unlock(&m);
//解鎖之后, 等待之前, 可能條件已經(jīng)滿(mǎn)足, 信號(hào)已經(jīng)發(fā)出, 但是該信號(hào)可能會(huì)被錯(cuò)過(guò)
cond_wait(&cv);
pthread_mutex_lock(&m);
}
上面的解鎖和等待不是原子操作。解鎖以后, 調(diào)用cond_wait之前,如果已經(jīng)有其他線(xiàn)程獲取到了互斥量, 并且滿(mǎn)足了條件, 同時(shí)發(fā)出了通知信號(hào), 那么cond_wait將錯(cuò)過(guò)這個(gè)信號(hào), 可能會(huì)導(dǎo)致線(xiàn)程永遠(yuǎn)處于阻塞狀態(tài)。所以解鎖加等待必須是一個(gè)原子性的操作, 以確保已經(jīng)注冊(cè)到事件的等待隊(duì)列之前, 不會(huì)有其他線(xiàn)程可以獲得互斥量。
那先注冊(cè)等待事件, 后釋放鎖不行嗎?注意, 條件等待是個(gè)阻塞型的接口, 不單單是注冊(cè)在事件的等待隊(duì)列上, 線(xiàn)程也會(huì)因此阻塞于此, 從而導(dǎo)致互斥量無(wú)法釋放, 其他線(xiàn)程獲取不到互斥量, 也就無(wú)法通過(guò)改變共享數(shù)據(jù)使等待的條件得到滿(mǎn)足, 因此這就造成了死鎖。
pthread_mutex_lock(&m);
while(condition_is_false)
pthread_cond_wait(&v,&m);//此處會(huì)阻塞
如果代碼運(yùn)行到此處, 則表示我們等待的條件已經(jīng)滿(mǎn)足了,
*并且在此持有了互斥量
在滿(mǎn)足條件的情況下, 做你想做的事情。
pthread_mutex_unlock(&m);
pthread_cond_wait函數(shù)只能由擁有互斥量的線(xiàn)程來(lái)調(diào)用, 當(dāng)該函數(shù)返回的時(shí)候, 系統(tǒng)會(huì)確保該線(xiàn)程再次持有互斥量, 所以這個(gè)接口容易給人一種誤解, 就是該線(xiàn)程一直在持有互斥量。事實(shí)上并不是這樣的。這個(gè)接口向系統(tǒng)聲明了我在PCB等待序列中之后, 就把互斥量給釋放了。這樣其他線(xiàn)程就有機(jī)會(huì)持有互斥量,操作共享數(shù)據(jù), 觸發(fā)變化, 使線(xiàn)程等待的條件得到滿(mǎn)足。
pthread_cond_wait內(nèi)部會(huì)進(jìn)行解鎖邏輯,則一定要先放到PCB等待序列中,再進(jìn)行解鎖。
while(condition_is_false)
pthread_cond_wait(&v,&m);//此處會(huì)阻塞
if(condition_is_false)
pthread_cond_wait(&v,&m);//此處會(huì)阻塞
喚醒以后, 再次檢查條件是否滿(mǎn)足, 是不是多此一舉?
因?yàn)閱拘阎写嬖谔摷賳拘?spurious wakeup) , 換言之,條件尚未滿(mǎn)足, pthread_cond_wait就返了。在一些實(shí)現(xiàn)中, 即使沒(méi)有其他線(xiàn)程向條件變量發(fā)送信號(hào), 等待此條件變量的線(xiàn)程也有可能會(huì)醒來(lái)。
條件滿(mǎn)足了發(fā)送信號(hào), 但等到調(diào)用pthread_cond_wait的線(xiàn)程得到CPU資源時(shí), 條件又再次不滿(mǎn)足了。好在無(wú)論是哪種情況, 醒來(lái)之后再次測(cè)試條件是否滿(mǎn)足就可以解決虛假等待的問(wèn)題。
pthread_cond_wait內(nèi)部實(shí)現(xiàn)邏輯:
將調(diào)用pthread_cond_wait函數(shù)的執(zhí)行流放入到PCB等待隊(duì)列當(dāng)中
解鎖
等待被喚醒
被喚醒之后:
1、從PCB等待隊(duì)列中移除出來(lái)
2、搶占互斥鎖
情況1:拿到互斥鎖,pthread_cond_wait就返回了
情況2:沒(méi)有拿到互斥鎖,阻塞在pthread_cond_wait內(nèi)部搶鎖的邏輯中
當(dāng)阻塞在pthread_cond_wait函數(shù)搶鎖邏輯中時(shí),一旦執(zhí)行流時(shí)間耗盡,意味著線(xiàn)程就被切換出來(lái)了,程序計(jì)數(shù)器就保存的是搶鎖的指令,上下文信息保存的就是寄存器的值
當(dāng)再次擁有CPU資源后,恢復(fù)搶鎖邏輯
直到搶鎖成功,pthread_cond_wait函數(shù)才會(huì)返回
7.3.3條件變量的喚醒
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
pthread_cond_signal負(fù)責(zé)喚醒等待在條件變量上的一個(gè)線(xiàn)程。
pthread_cond_broadcast,就是廣播喚醒等待在條件變量上的所有線(xiàn)程。
先發(fā)送信號(hào),然后解鎖互斥量,這個(gè)順序是必須的嘛?
先通知條件變量、 后解鎖互斥量, 效率會(huì)比先解鎖、 后通知條件變量低。因?yàn)橄韧ㄖ蠼怄i, 執(zhí)行pthread_cond_wait的線(xiàn)程可能在互斥量已然處于加鎖狀態(tài)的時(shí)候醒來(lái), 發(fā)現(xiàn)互斥量仍然沒(méi)有解鎖, 就會(huì)再次休眠, 從而導(dǎo)致了多余的上下文切換。
7.3.4條件變量的銷(xiāo)毀
int pthread_cond_destroy(pthread_cond_t *cond);
注意:
1、永遠(yuǎn)不要用一個(gè)條件變量對(duì)另一個(gè)條件變量賦值, 即pthread_cond_t cond_b = cond_a不合法, 這種行為是未定義的。
2、使用PTHREAD_COND_INITIALIZE靜態(tài)初始化的條件變量, 不需要被銷(xiāo)毀。
3、要調(diào)用pthread_cond_destroy銷(xiāo)毀的條件變量可以調(diào)用pthread_cond_init重新進(jìn)行初始化。
4、不要引用已經(jīng)銷(xiāo)毀的條件變量, 這種行為是未定義的。
例:
#include
在這里為什么有兩個(gè)條件變量呢?
若所有的線(xiàn)程只使用一個(gè)條件變量,會(huì)導(dǎo)致所有線(xiàn)程最后都進(jìn)入PCB等待隊(duì)列。
thread apply all bt查看:
7.3.5情況分析:兩個(gè)生產(chǎn)者,兩個(gè)消費(fèi)者,一個(gè)PCB等待隊(duì)列
1、最開(kāi)始的情況,兩個(gè)消費(fèi)者搶到了鎖,此時(shí)生產(chǎn)者未生產(chǎn),則都放入PCB等待隊(duì)列中
2、一個(gè)生產(chǎn)者搶到了鎖,生產(chǎn)了一份材料,喚醒一個(gè)消費(fèi)者,此時(shí)三者搶鎖,若兩個(gè)生產(chǎn)者分別先后搶到了鎖,則都進(jìn)入PCB等待隊(duì)列中
3、只有一個(gè)消費(fèi)者,則必會(huì)搶到鎖,消費(fèi)材料,喚醒PCB等待隊(duì)列,若此時(shí)喚醒的是,消費(fèi)者,則現(xiàn)在是這樣一個(gè)情況:
4、兩個(gè)消費(fèi)者在外邊搶鎖,一定都會(huì)進(jìn)入PCB等待隊(duì)列中
解決上述問(wèn)題可采用兩種方法:
1、使用int pthread_cond_broadcast(pthread_cond_t *cond);,喚醒PCB等待隊(duì)列中所有的線(xiàn)程。此時(shí)所有線(xiàn)程都會(huì)同時(shí)執(zhí)行搶鎖邏輯,太消費(fèi)資源了。此方法不妥
2、采用兩個(gè)PCB等待序列,一個(gè)放生產(chǎn)者,一個(gè)放消費(fèi)者,生產(chǎn)者喚醒消費(fèi)者,消費(fèi)者喚醒生產(chǎn)者。
8.線(xiàn)程取消8.1線(xiàn)程取消函數(shù)接口int pthread_cancel(pthread_t thread);
一個(gè)線(xiàn)程可以通過(guò)調(diào)用該函數(shù)向另一個(gè)線(xiàn)程發(fā)送取消請(qǐng)求。這不是個(gè)阻塞型接口, 發(fā)出請(qǐng)求后, 函數(shù)就立刻返回了, 而不會(huì)等待目標(biāo)線(xiàn)程退出之后才返回。
調(diào)用pthread_cancel時(shí), 會(huì)向目標(biāo)線(xiàn)程發(fā)送一個(gè)SIGCANCEL的信號(hào), 該信號(hào)就是kill -l中消失的32號(hào)信號(hào)。
線(xiàn)程的默認(rèn)取消狀態(tài)是PTHREAD_CANCEL_ENABLE。即是可被取消的。
什么是取消點(diǎn)?可通過(guò)man pthreads查看取消點(diǎn)
就是對(duì)于某些函數(shù), 如果線(xiàn)程允許取消且取消類(lèi)型是延遲取消, 并且線(xiàn)程也收到了取消請(qǐng)求, 那么當(dāng)執(zhí)行到這些函數(shù)的時(shí)候, 線(xiàn)程就可以退出了。
8.2線(xiàn)程取消帶來(lái)的弊端
目標(biāo)線(xiàn)程可能會(huì)持有互斥量、 信號(hào)量或其他類(lèi)型的鎖, 這時(shí)候如果收到取消請(qǐng)求, 并且取消類(lèi)型是異步取消, 那么可能目標(biāo)線(xiàn)程掌握的資源還沒(méi)有來(lái)得及釋放就被迫退出了, 這可能會(huì)給其他線(xiàn)程帶來(lái)不可恢復(fù)的后果, 比如死鎖(其他線(xiàn)程再也無(wú)法獲得資源) 。
注意:
輕易不要調(diào)用pthread_cancel函數(shù), 在外部殺死線(xiàn)程是很糟糕的做法,畢竟如果想通知目標(biāo)線(xiàn)程退出, 還可以采取其他方法。
如果不得不允許線(xiàn)程取消, 那么在某些非常關(guān)鍵不容有失的代碼區(qū)域, 暫時(shí)將線(xiàn)程設(shè)置成不可取消狀態(tài), 退出關(guān)鍵區(qū)域之后, 再恢復(fù)成可以取消的狀態(tài)。
在非關(guān)鍵的區(qū)域, 也要將線(xiàn)程設(shè)置成延遲取消, 永遠(yuǎn)不要設(shè)置成異步取消。
8.2線(xiàn)程清理函數(shù)
假設(shè)遇到取消請(qǐng)求, 線(xiàn)程執(zhí)行到了取消點(diǎn), 卻沒(méi)有來(lái)得及做清理動(dòng)作(如動(dòng)態(tài)申請(qǐng)的內(nèi)存沒(méi)有釋放, 申請(qǐng)的互斥量沒(méi)有解鎖等) , 可能會(huì)導(dǎo)致錯(cuò)誤的產(chǎn)生, 比如死鎖, 甚至是進(jìn)程崩潰。
為了避免這種情況, 線(xiàn)程可以設(shè)置一個(gè)或多個(gè)清理函數(shù), 線(xiàn)程取消或退出時(shí),會(huì)自動(dòng)執(zhí)行這些清理函數(shù), 以確保資源處于一致的狀態(tài)。
如果線(xiàn)程被取消, 清理函數(shù)則會(huì)負(fù)責(zé)解鎖操作。
void pthread_cleanup_push(void (*routine)(void *),void *arg);
void pthread_cleanup_pop(int execute);
這兩個(gè)函數(shù)必須同時(shí)出現(xiàn), 并且屬于同一個(gè)語(yǔ)法塊。
何時(shí)會(huì)觸發(fā)注冊(cè)的清理函數(shù):?
1、當(dāng)線(xiàn)程的主函數(shù)是調(diào)用pthread_exit返回的, 清理函數(shù)總是會(huì)被執(zhí)行。
2、當(dāng)線(xiàn)程是被其他線(xiàn)程調(diào)用pthread_cancel取消的, 清理函數(shù)總是會(huì)被執(zhí)行。
3、當(dāng)線(xiàn)程的主函數(shù)是通過(guò)return返回的, 并且pthread_cleanup_pop的唯一參數(shù)execute是0時(shí), 清理函數(shù)不會(huì)被執(zhí)行.
4、線(xiàn)程的主函數(shù)是通過(guò)return返回的, 并且pthread_cleanup_pop的唯一參數(shù)execute是非零值時(shí), 清理函數(shù)會(huì)執(zhí)行一次。
代碼:
#include
結(jié)果:只要拿到鎖,就表明線(xiàn)程清理函數(shù)成功了。
9.多線(xiàn)程與fork()
永遠(yuǎn)不要在多線(xiàn)程程序里面調(diào)用fork。
Linux的fork函數(shù), 會(huì)復(fù)制一個(gè)進(jìn)程, 對(duì)于多線(xiàn)程程序而言, fork函數(shù)復(fù)制的是用fork的那個(gè)線(xiàn)程, 而并不復(fù)制其他的線(xiàn)程。fork之后其他線(xiàn)程都不見(jiàn)了。Linux存在forkall語(yǔ)義的系統(tǒng)調(diào)用, 無(wú)法做到將多線(xiàn)程全部復(fù)制。
多線(xiàn)程程序在fork之前, 其他線(xiàn)程可能正持有互斥量處理臨界區(qū)的代碼。fork之后, 其他線(xiàn)程都不見(jiàn)了, 那么互斥量的值可能處于不可用的狀態(tài), 也不會(huì)有其他線(xiàn)程來(lái)將互斥量解鎖。
10.生產(chǎn)者與消費(fèi)者模型10.1生產(chǎn)者與消費(fèi)者模型的本質(zhì)
本質(zhì)上是一個(gè)線(xiàn)程安全的隊(duì)列,和兩種角色的線(xiàn)程(生產(chǎn)者和消費(fèi)者)
存在三種關(guān)系:
1、生產(chǎn)者與生產(chǎn)者互斥
2、消費(fèi)者與消費(fèi)者互斥
3、生產(chǎn)者與消費(fèi)者同步+互斥
10.2為什么需要生產(chǎn)者與消費(fèi)者模型?
生產(chǎn)者和消費(fèi)者彼此之間不直接通訊,而通過(guò)阻塞隊(duì)列來(lái)進(jìn)行通訊,所以生產(chǎn)者生成完數(shù)據(jù)之后不用等待消費(fèi)者處理,直接扔給阻塞隊(duì)列,消費(fèi)者不找生產(chǎn)者要數(shù)據(jù),而是直接從阻塞隊(duì)列中取,阻塞隊(duì)列就相當(dāng)于一個(gè)緩沖區(qū),平衡了生產(chǎn)者和消費(fèi)者的處理能力。這個(gè)阻塞隊(duì)列就是用來(lái)給生產(chǎn)者和消費(fèi)解耦的。
10.3優(yōu)點(diǎn)
1、解耦
2、支持高并發(fā)
3、支持忙閑不均
10.4實(shí)現(xiàn)兩個(gè)消費(fèi)者線(xiàn)程,兩個(gè)生產(chǎn)者線(xiàn)程的生產(chǎn)者消費(fèi)者模型
生產(chǎn)者生成時(shí)用的同一個(gè)全局變量,故對(duì)該全局變量進(jìn)行了加鎖。
#include
先考慮代碼的核心邏輯(先實(shí)現(xiàn))
考慮核心邏輯中是否訪問(wèn)臨界資源或者說(shuō)執(zhí)行臨界區(qū)代碼,如果有就需要保持互斥
考慮線(xiàn)程之間是否需要同步

發(fā)表評(píng)論
請(qǐng)輸入評(píng)論內(nèi)容...
請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字
圖片新聞
最新活動(dòng)更多
-
7月8日立即報(bào)名>> 【在線(xiàn)會(huì)議】英飛凌新一代智能照明方案賦能綠色建筑與工業(yè)互聯(lián)
-
7月22-29日立即報(bào)名>> 【線(xiàn)下論壇】第三屆安富利汽車(chē)生態(tài)圈峰會(huì)
-
7月31日免費(fèi)預(yù)約>> OFweek 2025具身機(jī)器人動(dòng)力電池技術(shù)應(yīng)用大會(huì)
-
7.30-8.1火熱報(bào)名中>> 全數(shù)會(huì)2025(第六屆)機(jī)器人及智能工廠展
-
免費(fèi)參會(huì)立即報(bào)名>> 7月30日- 8月1日 2025全數(shù)會(huì)工業(yè)芯片與傳感儀表展
-
即日-2025.8.1立即下載>> 《2024智能制造產(chǎn)業(yè)高端化、智能化、綠色化發(fā)展藍(lán)皮書(shū)》
推薦專(zhuān)題
- 1 AI 眼鏡讓百萬(wàn) APP「集體失業(yè)」?
- 2 豆包前負(fù)責(zé)人喬木出軌BP后續(xù):均被辭退
- 3 一文看懂視覺(jué)語(yǔ)言動(dòng)作模型(VLA)及其應(yīng)用
- 4 “支付+”時(shí)代,支付即生態(tài) | 2025中國(guó)跨境支付十大趨勢(shì)
- 5 中國(guó)最具實(shí)力AI公司TOP10
- 6 特斯拉Robotaxi上路,馬斯克端上畫(huà)了十年的餅
- 7 國(guó)家數(shù)據(jù)局局長(zhǎng)劉烈宏調(diào)研格創(chuàng)東智
- 8 AI的夏天:第四范式VS云從科技VS地平線(xiàn)機(jī)器人
- 9 張勇等人退出阿里合伙人
- 10 深圳跑出40億超級(jí)隱形冠軍:賣(mài)機(jī)器人年入6.1億,港股上市