欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

目錄

柚子快報(bào)邀請(qǐng)碼778899分享:運(yùn)維 linux:線程同步

柚子快報(bào)邀請(qǐng)碼778899分享:運(yùn)維 linux:線程同步

http://yzkb.51969.com/

個(gè)人主頁(yè) : 個(gè)人主頁(yè) 個(gè)人專欄 : 《數(shù)據(jù)結(jié)構(gòu)》 《C語(yǔ)言》《C++》《Linux》

文章目錄

前言線程同步條件變量接口簡(jiǎn)單示例pthread_cond_wait為什么要有mutex偽喚醒問(wèn)題的解決 (if->while)

總結(jié)

前言

本文作為我對(duì)于線程同步知識(shí)總結(jié)

線程同步

同步:在保證數(shù)據(jù)安全的前提下,讓線程能夠按照某種順序訪問(wèn)臨界資源,從而有效避免饑餓問(wèn)題,叫做同步競(jìng)態(tài)條件:是指多個(gè)線程同時(shí)訪問(wèn)系統(tǒng)共享資源時(shí),由于其執(zhí)行順序或時(shí)間上的不確定性,導(dǎo)致數(shù)據(jù)不一致或其它不可預(yù)料的結(jié)果(一般發(fā)生在對(duì)稱多處理環(huán)境,中斷和異常處理,內(nèi)核態(tài)搶占,并發(fā)執(zhí)行…)

看了上面兩個(gè)概念,你可能還是不太理解同步是什么,為什么要有同步。下面我們就舉一個(gè)例子。 我們假定有兩個(gè)人,一個(gè)人A將蘋果放在桌子上,另一個(gè)人B蒙著眼睛去桌子上拿蘋果,桌子每次只允許有一個(gè)人,因?yàn)锽不清楚桌子上的情況是什么(有一個(gè)蘋果,沒(méi)有蘋果,桌子上全是蘋果),那為了保險(xiǎn)起見,B只能瘋狂的去桌子上拿蘋果,以保證B拿到所有的蘋果。那如果桌子上沒(méi)有蘋果,B仍然瘋狂去桌子上拿蘋果,此時(shí)A是不是就不能去桌子上放蘋果,那此時(shí)B是不是再做無(wú)用工,而且導(dǎo)致了A不能放蘋果,B拿蘋果的效率降低。如果我們將A,B換成線程,蘋果看出共享資源(某種任務(wù)),桌子看成臨界區(qū),那B是不是就是一直在做申請(qǐng)鎖,再釋放鎖的無(wú)效工作,并且導(dǎo)致了A的饑餓問(wèn)題。這時(shí)我們就需要保證A,B之間的順序問(wèn)題,如在B訪問(wèn)過(guò)桌子后,不能立即再次訪問(wèn)桌子,要等待A訪問(wèn)桌子后。這是不是就會(huì)使A,B拿蘋果的效率提升。而這就是為什么要有同步的理由

條件變量接口

初始化條件變量

靜態(tài)初始化 與互斥鎖類似,定義一個(gè)全局的條件變量,用PTHREAD_COND_INITIALIZER宏來(lái)初始化,系統(tǒng)自動(dòng)釋放該條件變量。該宏一般存放在 /usr/include/pthread.h 路徑下 動(dòng)態(tài)初始化 restrict是C語(yǔ)言的一個(gè)關(guān)鍵字,表示該指針是唯一的訪問(wèn)其指向?qū)ο蟮闹羔槨?cond將被初始化的條件變量,attr 為nullptr,使用默認(rèn)屬性初始化條件變量。 如果函數(shù)成功執(zhí)行,返回0; 如果函數(shù)執(zhí)行失敗,則返回錯(cuò)誤碼,如EAGAIN(資源暫時(shí)不可用),ENOMEM(內(nèi)存不足)

銷毀條件變量 cond 表示將被銷毀的條件變量,需要注意在調(diào)用pthread_cond_destroy后,該指針本身并未被銷毀,只是所指向的條件變量被銷毀,記得將指針置空 如果函數(shù)成功執(zhí)行,返回0; 如果函數(shù)失敗,返回錯(cuò)誤碼。如EBUSY,該條件變量正在被使用

等待條件變量 cond 表示將要等待的條件變量,mutex 表示線程所持有的互斥鎖 如果函數(shù)成功執(zhí)行,返回0;如果函數(shù)執(zhí)行失敗,返回錯(cuò)誤碼,如EINVAL 無(wú)效的參數(shù)(條件變量 or 互斥鎖為初始化…)

關(guān)于該函數(shù)的參數(shù)為什么會(huì)有鎖,有什么注意事項(xiàng),在下面代碼示例,我們?cè)俳忉尅?/p>

喚醒等待

cond要發(fā)生信號(hào)的條件變量指針。 如果函數(shù)執(zhí)行成功,返回0; 如果函數(shù)執(zhí)行失敗,返回錯(cuò)誤碼,如ENVAL(無(wú)效的參數(shù)) 需要注意的是,pthread_cond_signal只用于喚醒在cond條件變量的阻塞隊(duì)列中等待的一個(gè)線程。

該函數(shù)的參數(shù)與返回值與pthread_cond_signal相同,只不過(guò)該函數(shù)喚醒所有在cond條件變量的阻塞隊(duì)列中等待的所有線程,而那些線程先執(zhí)行,取決于操作系統(tǒng)的調(diào)度策略。

簡(jiǎn)單示例

我們先來(lái)看看下面代碼,3個(gè)線程爭(zhēng)奪ticket資源。當(dāng)三個(gè)線程檢測(cè)到ticket == 0時(shí),三個(gè)線程都將等待。我們主線程每過(guò)5秒,使ticket += 10。

#include

#include

#include

#include

using namespace std;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

int ticket = 100;

void* threadRoutine(void *args)

{

const string threadname = static_cast(args);

while(true)

{

usleep(1000);

pthread_mutex_lock(&mutex);

if(ticket > 0)

{

ticket--;

cout << threadname << ", get a ticket: " << ticket << endl;

}

else

{

cout << threadname << ", ticket == 0" << endl;

pthread_cond_wait(&cond, &mutex);

}

pthread_mutex_unlock(&mutex);

}

return nullptr;

}

int main()

{

pthread_t td1;

pthread_create(&td1, nullptr, threadRoutine, (void*)"thread-1");

pthread_t td2;

pthread_create(&td2, nullptr, threadRoutine, (void*)"thread-2");

pthread_t td3;

pthread_create(&td3, nullptr, threadRoutine, (void*)"thread-3");

while(true)

{

sleep(5);

pthread_mutex_lock(&mutex);

ticket += 10;

pthread_mutex_unlock(&mutex);

pthread_cond_signal(&cond);

}

pthread_join(td1, nullptr);

pthread_join(td2, nullptr);

pthread_join(td3, nullptr);

return 0;

}

當(dāng)線程2,線程3,線程1先后檢測(cè)到ticket == 0時(shí),在cond的等待隊(duì)列中,線程以2,3,1的順序排隊(duì)。那當(dāng)調(diào)用pthread_cond_signal函數(shù)時(shí),線程2會(huì)先執(zhí)行,執(zhí)行完再檢測(cè)到ticket==0,排到等待隊(duì)列尾部 再調(diào)用pthread_cond_signal函數(shù)時(shí),線程3會(huì)執(zhí)行。 再調(diào)用pthread_cond_signal函數(shù)時(shí),線程1會(huì)執(zhí)行。 這樣,我們多線程就可以按某種特定順序來(lái)執(zhí)行。 那如果我們使用pthread_cond_broadcast函數(shù),會(huì)有什么情況? 我們會(huì)發(fā)現(xiàn),三個(gè)線程都被喚醒,來(lái)爭(zhēng)搶ticket資源,其先后順序由操作系統(tǒng)決定(優(yōu)先級(jí),競(jìng)爭(zhēng)鎖的能力…)。

pthread_cond_wait為什么要有mutex

此時(shí)不知道你是否有一個(gè)疑問(wèn),我們假定線程-1先爭(zhēng)搶到ticket,檢測(cè)到ticket == 0時(shí),該線程-1要在cond的等待隊(duì)列中等待,然后其它兩個(gè)線程在進(jìn)入臨界區(qū),檢測(cè)到ticket==0,在等待隊(duì)列中排隊(duì)。但是線程-1是持有鎖進(jìn)入等待隊(duì)列的,那其它兩個(gè)線程是如何進(jìn)入臨界區(qū)的?答案很明顯,那就是線程-1在cond等待中,一定釋放了其持有的鎖,從而使其余兩個(gè)線程可以持有鎖進(jìn)入臨界區(qū)。這就是為什么pthread_cond_wait函數(shù)的參數(shù)要有互斥鎖的存在。 那我們?cè)谏钊胂胍幌?,調(diào)用pthread_cond_wait函數(shù)后,該線程是先釋放鎖,再進(jìn)入等待隊(duì)列中;還是先進(jìn)入等待隊(duì)列中,再釋放鎖?答案是都不是。釋放鎖和進(jìn)入等待隊(duì)列是同時(shí)進(jìn)行的?。?!這也表示pthread_cond_wait函數(shù)是原子的,在調(diào)用pthread_cond_wait時(shí),涉及的互斥鎖釋放和進(jìn)入等待隊(duì)列的操作是作為一個(gè)不可分割的整體來(lái)執(zhí)行。確保了線程在調(diào)用該函數(shù)時(shí)不會(huì)遇到競(jìng)態(tài)條件,即線程在釋放鎖和進(jìn)入等待隊(duì)列之間不會(huì)被其它線程打斷。 以下是線程調(diào)用pthread_cond_wait的過(guò)程

線程必須已經(jīng)持有鎖:在調(diào)用pthread_cond_wait時(shí),線程必須已經(jīng)鎖定了某個(gè)互斥鎖,這是該函數(shù)的前提條件 自動(dòng)釋放互斥鎖:當(dāng)線程調(diào)用pthread_cond_wait時(shí),它會(huì)自動(dòng)釋放它當(dāng)前持有的互斥鎖。這一步是為了允許其它線程有機(jī)會(huì)獲取該互斥鎖并修改共享資源,從而可能改變條件變量的狀態(tài) 加入等待隊(duì)列:釋放互斥鎖之后,線程會(huì)接著被添加到條件變量的等待隊(duì)列中,并在此處等待 等待被喚醒:線程在等待隊(duì)列中等待,直到其它線程調(diào)用pthread_cond_signal 或 pthread_cond_broadcast來(lái)喚醒它 重新獲取互斥鎖:當(dāng)線程被喚醒時(shí),線程會(huì)嘗試重新獲取之前釋放的互斥鎖。如果鎖此時(shí)沒(méi)有被其它線程持有,線程將成功獲取鎖并繼續(xù)執(zhí)行。如果鎖仍然被其它線程持有,線程將阻塞(在申請(qǐng)鎖的地方阻塞),直到能夠獲取鎖時(shí)。

具體來(lái)說(shuō),pthread_cond_wait函數(shù)的內(nèi)部實(shí)現(xiàn)保證了2,3步驟的原子性。

偽喚醒問(wèn)題的解決 (if->while)

偽喚醒問(wèn)題是指:在多線程環(huán)境中,當(dāng)線程等待某個(gè)條件變量時(shí),它可能會(huì)在沒(méi)有到達(dá)預(yù)期的情況下被喚醒。 對(duì)于這一問(wèn)題,我們可以在判斷的時(shí)候,將if 變?yōu)?while,使其被喚醒后任然進(jìn)行條件判斷,如果條件滿足,線程繼續(xù)向后執(zhí)行,如果條件不被滿足,線程繼續(xù)在該條件變量下等待。

pthread_mutex_lock(&mutex);

// 訪問(wèn)臨界區(qū)

while(條件為假)

pthread_cond_wait(&cond, &mutex);

pthread_mutex_unlock(&mutex);

總結(jié)

以上就是我對(duì)于線程同步的總結(jié)。

柚子快報(bào)邀請(qǐng)碼778899分享:運(yùn)維 linux:線程同步

http://yzkb.51969.com/

精彩內(nèi)容

評(píng)論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。

轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://m.gantiao.com.cn/post/18795113.html

發(fā)布評(píng)論

您暫未設(shè)置收款碼

請(qǐng)?jiān)谥黝}配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問(wèn)

文章目錄