當前位置:首頁 > 公眾號精選 > CPP開發(fā)者
[導讀]眾所周知,STL容器不是線程安全的。對于vector,即使寫方(生產(chǎn)者)是單線程寫入,但是并發(fā)讀的時候,由于潛在的內存重新申請和對象復制問題,會導致讀方(消費者)的迭代器失效。實際表現(xiàn)也就是招致了coredump。另外一種情況,如果是多個寫方,并發(fā)的push_back(),也會導...

眾所周知,STL容器不是線程安全的。對于vector,即使寫方(生產(chǎn)者)是單線程寫入,但是并發(fā)讀的時候,由于潛在的內存重新申請和對象復制問題,會導致讀方(消費者)的迭代器失效。實際表現(xiàn)也就是招致了core dump。另外一種情況,如果是多個寫方,并發(fā)的push_back(),也會導致core dump。

解法一

加鎖是一種解決方案,比如互斥鎖std::mutex。但是加std::mutex確實性能較差。對于多讀少寫的場景可以用讀寫鎖(也叫共享獨占鎖)來緩解。比如C 17引入了std::shared_mutex 。更多鎖的種類可以閱讀之前寫的這篇文章:

如何理解互斥鎖、條件變量、讀寫鎖以及自旋鎖?

當然本文的目的自然不是自我重復再次介紹一次鎖的使用,請繼續(xù)閱讀解法二!

解法二

更多的時候,其實可以通過固定vector的大小,避免動態(tài)擴容(無push_back)來做到lock-free!

即在開始并發(fā)讀寫之前(比如初始化)的時候,給vector設置好大小。

struct?Data?{
...
};
vector?v;
v.resize(1000);
注意是resize(),不是reserve()!

可能大家平時用reserve()比較多,顧名思義,reserve就是預留內存。為的是避免內存重新申請以及容器內對象的拷貝。說白了,reserve()是給push_back()準備的!

而resize除了預留內存以外,還會調用容器元素的構造函數(shù),不僅分配了N個對象的內存,還會構造N個對象。從這個層面上來說,resize()在時間效率上是比reserve()低的。但是在多線程的場景下,用resize再合適不過。

你可以resize好N個對象,多線程不管是讀還是寫,都是通過容器的下標訪問operator[]來訪問元素,不要push_back()新元素。所謂的『寫操作』在這里不是插入新元素,而是修改舊元素。

如果N的最大個數(shù)是可以預期的就直接設置就好,如果沒辦法預期就再把vector搞成ring buffer(環(huán)形隊列)來緩解壓力。

可以給元素類加上成員變量標記當前的讀寫狀態(tài)、是否被消費等等。

當然,你會說,如果B,C,D,E,F(xiàn)這個5個線程是等價的,要不停消費vector中的元素,會造成重復消費不?

當然會。你可以把隊列頭的下標定義成原子變量(std::atomic),盡管原子變量也需要做線程同步,但是比一般的鎖開銷要小很多啦。

如果你想連原子變量也不用,有沒有辦法呢?有啊。那就給B,C,D,E,F(xiàn)分配不同的消費隊列啊。比如當前有5個讀線程,那么每個線程就消費下標對5取模之后的某個固定結果的下標。比如:

  • B消費:0、5、10、15、……
  • C消費:1、6、11、16、……
  • D消費:2、7、12、17、……
  • E消費:3、8、13、18、……
  • F消費:4、9、14、19、……
每個讀線程各自維護自己當前消費的最新下標。

這樣做有啥問題沒?也有,就是可能會導致不同的線程繁忙和等待的情況差異巨大:忙的忙死,閑的閑死。具體場景具體分析,總之,無論如何要控制住。不要讓一個任務hang住整個線程。

vector是順序容器,STL中還有一類關聯(lián)容器其線程安全問題也不容小覷。比如map、unordered_map。

我們可能會有這樣一種場景:在并發(fā)環(huán)境下,收集一些Key-Value,存儲在某一個公共的容器中。這里也談一下不用鎖的方案,當然做不到放之四海皆準。它有一些限制條件,只能看是否滿足你的需要了。

當有多個寫線程對情況下,并發(fā)地插入 map/unordered_map都會引發(fā)core dump。對此,在某些場景下也可以避免加鎖:如果全量的key有辦法在并發(fā)之前就能拿到的,那么就對這個map,提前做一下insert。

并發(fā)環(huán)境中如果只是修改value,而不是插入新key就不會core dump!不過如果你沒辦法保證多個寫線程不會同時修改同一個key的value,那么可能存在value的覆蓋。

無法保證這點時,還是需要加鎖。不過可以對key采取某種hash策略轉成整型,然后進行分段加鎖,減少一點鎖沖突的概率,或者用一下CAS的策略。

另外對于unordered_map,在單寫多讀的多線程場景下,會不會有問題呢?也可能有。gcc 4.7.2的unordered_map實現(xiàn)曾被爆出有這個問題。原因的新插入的元素,觸發(fā)了rehash,讓其他線程在unordered_map中查找的過程之中,出現(xiàn)了core dump。見:

https://stackoverflow.com/questions/16353334/segv-in-gccs-stdunordered-map

我不確定clang以及后續(xù)的gcc版本是否還有此問題。應該在不添加任何額外同步代碼的情況下,無法解決。

容器并發(fā)前初始化與偽共享的爭議

本文內容曾經(jīng)在知乎上寫過,有網(wǎng)友評論:解法二會有false sharing(偽共享)的問題。

這里簡單回應一下,談論偽共享,要考慮具體的場景。的確某些時候偽共享會帶來性能損失,但是要和并行化帶來的性能提升來比較,孰高孰低。如果并行提升的性能足夠多,是足以彌補這點偽共享的損失的。

比如我要進行遠程IO,我有N個key要查詢redis,把他們的結果存儲到一個vector中,這個vector的寫入操作在IO的異步回調函數(shù)中。在不加任何額外處理的情況下,極大概率會導致vector的core dump。

而如果vector初始化一下,則無需在回調函數(shù)中加鎖,就能保證安全。這時候并行IO本身帶來的性能提升,遠遠大于可能的偽共享帶來損失。

這里為什么說可能呢?因為偽共享的觸發(fā)沒你想象的這么簡單。如何成功模擬出一次偽共享帶來性能損失的例子?你可以寫程序自測一下,并不容易……甚至你改一下優(yōu)化級別,改成O2,測試表現(xiàn)都很不一樣。

一般網(wǎng)絡上談論偽共享時所舉的例子,并不是一個vector中多個元素之間并行讀寫觸發(fā)了偽共享。而是vector的元素類型是一個對象,對象中有2個數(shù)據(jù)字段a和b,在多線程分別更新同一個元素的a和b字段的時候,導致了偽共享。

比如一個線程更新vector中每個元素的a字段,另外一個線程更新vector中每個元素的b字段。

Anyway,偽共享的議題比較復雜,歡迎留意評論!


- EOF -

本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內容真實性等。需要轉載請聯(lián)系該專欄作者,如若文章內容侵犯您的權益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或將催生出更大的獨角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉型技術解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關鍵字: 汽車 人工智能 智能驅動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務中斷的風險,如企業(yè)系統(tǒng)復雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務連續(xù)性,提升韌性,成...

關鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質量流程IT總裁陶景文發(fā)表了演講。

關鍵字: 華為 12nm EDA 半導體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權最終是由生態(tài)的繁榮決定的。

關鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務引領增長 以科技創(chuàng)新為引領,提升企業(yè)核心競爭力 堅持高質量發(fā)展策略,塑強核心競爭優(yōu)勢...

關鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術學會聯(lián)合牽頭組建的NVI技術創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術創(chuàng)新聯(lián)...

關鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關鍵字: BSP 信息技術
關閉
關閉