欧美人与性动交α欧美精品_色综合久久天天综合_亚洲s黄在线_youjizz国产在线观看_男女猛烈拍拍拍无挡视频免费

首頁(yè) > 資訊 > > 正文

鎖會(huì)帶來(lái)多大開(kāi)銷(C++)

2023-07-02 00:17:39        來(lái)源:   嗶哩嗶哩

不知道你有沒(méi)有聽(tīng)說(shuō)過(guò),隔壁Java的鎖并不是“普通”的鎖,它有一個(gè)鎖升級(jí)策略,java里面有一系列鎖的實(shí)現(xiàn),從輕量級(jí)到重量級(jí)分為偏向鎖,樂(lè)觀鎖,悲觀鎖。當(dāng)情況變?cè)愀鈺r(shí)(長(zhǎng)時(shí)間不能獲得鎖),java會(huì)自動(dòng)將鎖替換成更重量級(jí)的鎖。

當(dāng)我第一次知道這件事的時(shí)候,我覺(jué)得這真是一個(gè)好辦法,當(dāng)情況允許,要盡可能用輕量級(jí)的鎖。


(資料圖片)

然而,我們常用的std::mutex,真的是一個(gè)“悲觀”的鎖嗎?

當(dāng)沒(méi)有爭(zhēng)用時(shí),std::mutex的性能

perfbench是一個(gè)c++性能測(cè)試網(wǎng)站,我們提交了三個(gè)測(cè)試樣例,我們看到箱線圖上有四根線,它們從左邊開(kāi)始分別是

1. ?std::unique_lock?lock(m);

2. ?std::lock_guard?lock(m);

3.? 自旋鎖,ato是一個(gè)原子變量

bool?expected?=?false;

while(!_exchange_weak(expected,?true,

std::memory_order_acquire,

std::memory_order_relaxed))

expected?=?false;

(false?,?std::memory_order_release);

4. 這是一個(gè)對(duì)照組。g是一個(gè)volatile的全局變量。

for(int?i=0;?i<40;?i++)?g++;?

volatile保證了這個(gè)循環(huán)不會(huì)被優(yōu)化掉,而且每次都從內(nèi)存中讀寫(xiě)變量g。

volatile是一個(gè)非常不常用的關(guān)鍵字,絕大多數(shù)人沒(méi)有理由去用它。如果你熟悉java,你應(yīng)該知道java中也有volatile關(guān)鍵字,而且還挺常用的,但是我想提醒你注意的是,java中volatile關(guān)鍵字和c++中volatile關(guān)鍵字語(yǔ)義并不一樣。java中的volatile幾乎可以當(dāng)作原子變量用了,它包含了內(nèi)存屏障方面的語(yǔ)義。但c++的volatile沒(méi)有這一層含義。所以在c++中,對(duì)volatile變量的讀寫(xiě)應(yīng)該被看做一次普通的內(nèi)存讀寫(xiě)。

我們可以在箱線圖上看出,四個(gè)樣例用時(shí)大致相當(dāng),也就是說(shuō),在可以獲得鎖時(shí),獲得鎖的消耗大約相當(dāng)于35次內(nèi)存讀寫(xiě)。在這個(gè)測(cè)試網(wǎng)站上,大約是20ns左右。(這個(gè)網(wǎng)站每個(gè)測(cè)試大約有15ns的固定開(kāi)銷,需要從結(jié)果中減去)。這個(gè)消耗和“標(biāo)準(zhǔn)”的自旋鎖相當(dāng)。

自旋鎖還是mutex

當(dāng)不能獲取鎖(其他線程獲得了鎖)時(shí),可能會(huì)發(fā)生上下文切換,當(dāng)前線程掛起,直到另一個(gè)線程退出加鎖區(qū)域,當(dāng)前線程重新回到就緒態(tài)然后排隊(duì)等待運(yùn)行。

系統(tǒng)上下文切換的開(kāi)銷一般認(rèn)為是相對(duì)大的

我們g++的循環(huán)的開(kāi)銷是L1緩存讀取這個(gè)級(jí)別的。按這張圖片的說(shuō)法,如果說(shuō)在可以獲得鎖時(shí),請(qǐng)求一個(gè)鎖的開(kāi)銷是從房間的一端走到另一端,上下文切換的開(kāi)銷大約就相當(dāng)于跑3公里。

自旋鎖可以避免上下文切換的開(kāi)銷,我們用一個(gè)死循環(huán)等待另一個(gè)線程退出加鎖區(qū)域,如果另一個(gè)線程能夠很快退出加鎖區(qū)域,那么我們的死循環(huán)就不用持續(xù)多久。

但是另一個(gè)線程能夠很快退出加鎖區(qū)域的必要條件是,它當(dāng)前正在另一個(gè)cpu核心上運(yùn)行。如果它正在排隊(duì)等待調(diào)度的話,那么可以預(yù)見(jiàn)的,我們的死循環(huán)可能要跑不少時(shí)間。我們不太能預(yù)見(jiàn)我們的線程需要排多久隊(duì),這有可能引發(fā)非常糟糕的情況。

這里有一篇文章,/blog/2020/07/06/,l它舉了各種各樣的例子,其中粉色的是使用自旋鎖的情況

現(xiàn)在看起來(lái)一切都好,然而當(dāng)線程數(shù)超過(guò)核心數(shù)時(shí),災(zāi)難發(fā)生了。

那么解決辦法是什么呢?混合鎖。請(qǐng)求一個(gè)鎖時(shí),如果不能獲得鎖,先自旋等待,自旋一段時(shí)間不能獲得鎖,就屈服,請(qǐng)求互斥鎖。

然而幸運(yùn)的是,現(xiàn)代系統(tǒng)中,crt的鎖都是混合鎖。也就是說(shuō),我們幾乎不需要做任何額外的操作就能享受自旋鎖和互斥鎖兩者的優(yōu)點(diǎn)!或者說(shuō)std::mutex雖然不要求使用類似java鎖升級(jí)的策略,但是本質(zhì)上,它的確有類似鎖升級(jí)的機(jī)制!

總結(jié)

大部分情況下,std::mutex已經(jīng)足夠好了。幾乎沒(méi)有理由去寫(xiě)一個(gè)自旋鎖。

std::mutex及不過(guò)分樂(lè)觀,也不過(guò)分悲觀,有一種能適應(yīng)絕大多數(shù)情況的美。

標(biāo)簽:

熱門(mén)話題
精彩推薦
今日推薦
花木