并发数据结构-1.1 并发的数据结构的设计
原文鏈接,譯文鏈接,譯者:董明鑫,校對:周可人
隨著多個處理器共享同一內(nèi)存的機器在商業(yè)上的廣泛使用,并發(fā)編程的藝術(shù)也產(chǎn)生了巨大的變化。當前的趨勢向著低功耗芯片級多線程(CMT)發(fā)展,所以這樣的機器一定會更加廣泛的被使用。
共享內(nèi)存多處理器是指并發(fā)的執(zhí)行多個線程的系統(tǒng),這些線程在共享的內(nèi)存中通過數(shù)據(jù)結(jié)構(gòu)通訊和同步。這些數(shù)據(jù)結(jié)構(gòu)的效率對于性能是很關(guān)鍵的,而目前熟練掌握為多處理器機器設(shè)計高效數(shù)據(jù)結(jié)構(gòu)這一技術(shù)的人并不多。對大多數(shù)人來說,設(shè)計并發(fā)的數(shù)據(jù)結(jié)構(gòu)比設(shè)計單線程的難多了,因為并發(fā)執(zhí)行的線程可能會多種方式地交錯運行他們的指令,每一種方式會帶來不同的,甚至不符合預期的輸出。這就要求設(shè)計者改變他們對運算的認識,理解新的設(shè)計方法,采用新的編程工具集。此外,設(shè)計可擴展的并發(fā)數(shù)據(jù)結(jié)構(gòu),使得當機器執(zhí)行越來越多的并發(fā)線程時依舊表現(xiàn)良好也是新的挑戰(zhàn)。本文主要介紹設(shè)計并發(fā)數(shù)據(jù)結(jié)構(gòu)的相關(guān)挑戰(zhàn),和一些重要的數(shù)據(jù)結(jié)構(gòu)相關(guān)內(nèi)容的總結(jié)。我們的總結(jié)絕不是全面的;相反,我們特意選取了一些能說明設(shè)計的關(guān)鍵問題的流行的數(shù)據(jù)結(jié)構(gòu),希望我們提供了足夠的背景和知識,讓有興趣的讀者接觸那些我們沒有提到的內(nèi)容。
1.1 并發(fā)的數(shù)據(jù)結(jié)構(gòu)的設(shè)計
共享內(nèi)存多處理器的一些特性使得并發(fā)數(shù)據(jù)結(jié)構(gòu)的設(shè)計和校驗比相對應的單線程結(jié)構(gòu)難度顯著增加。
acquire(Lock);
oldval = X;????????????????????????????????????????????????????????????????????????????????????? oldval = X;
X = oldval + 1;??????????????????????????????????????????????????????????????????????????????? X = oldval + 1;
return oldval;??????????????????????????????????????????????????????????????????????????????? ?release(Lock);
return oldval;
圖1.1:順序的和基于鎖機制的fetch-and-inc操作代碼片段
難點的根源在于并發(fā):因為線程是在不同的處理器上并發(fā)的執(zhí)行,而且受操作系統(tǒng)的調(diào)度決策、缺頁、中斷等等影響,我們必須按照全部異步的想法來思考,以保證不同的線程能夠隨意交錯的運行。這顯著提升了正確設(shè)計并發(fā)數(shù)據(jù)結(jié)構(gòu)的復雜度。
為多處理器系統(tǒng)設(shè)計并發(fā)的數(shù)據(jù)結(jié)構(gòu)在性能和可擴展性上也有大量的挑戰(zhàn)。在現(xiàn)代的機器上,處理器和內(nèi)存的布局、數(shù)據(jù)在內(nèi)存中的布局、多處理器體系結(jié)構(gòu)中各個元素間的通信負載全都對性能有影響。此外,正確性和性能兩者聯(lián)系非常的緊密:算法的改進在提高性能的同時經(jīng)常使其更加難以設(shè)計和檢驗正確的數(shù)據(jù)結(jié)構(gòu)實現(xiàn)。
下面的例子闡述了影響數(shù)據(jù)結(jié)構(gòu)設(shè)計的各個多處理器特征。假設(shè)我們想要實現(xiàn)一個共享的計數(shù)器數(shù)據(jù)結(jié)構(gòu),用于支持fetch-and-inc操作,即計數(shù)器加一然后返回增加前的值。一個普通的順序fetch-and-inc實現(xiàn)的代碼就如圖1.1中左邊部分所展示的那樣。
如果我們允許多個線程并發(fā)地調(diào)用fetch-and-inc操作,上述實現(xiàn)運行起來并不正確。來看看原因,注意大多數(shù)編譯器會把這份源代碼轉(zhuǎn)換成機器指令:把 X 的值裝進一個寄存器,然后把寄存器中的值加一,然后再把這個寄存器的值存回 X 。假如計數(shù)器初始化為 0 ,兩個不同的處理器并發(fā)的執(zhí)行兩個fetch-and-inc操作。然后就有可能兩個操作都從 X 中讀出 0 ,然后都把 1 存回 X 并且返回 0 。這顯然是不正確的:兩個操作中有一個應該返回 1 。
如上所述,兩個fetch-and-inc操作不正確的交錯結(jié)果導致了不正確的行為。一個自然并且普通的方法來阻止這樣的交錯就是用互斥鎖(也被叫做 mutex 或者 lock)。鎖是一個在任意時間點,都是不被(其他線程)獲取,只被一個線程所獲取的構(gòu)造。如果一個線程 t1 希望獲取已經(jīng)被另一個線程 t2 所獲取到的鎖,那么 t1 必須等到 t2 釋放這個鎖。
如圖 1.1 右半部分所示,我們能通過鎖機制得到一個正確的順序?qū)崿F(xiàn)。我們通過阻止所有的交錯來預防壞的交錯。這樣很容易得到一個正確的共享計數(shù)器,然而這種簡單是有代價的:鎖機制引發(fā)了許多關(guān)于性能和軟件工程上的問題。
文章轉(zhuǎn)自?并發(fā)編程網(wǎng)-ifeve.com
總結(jié)
以上是生活随笔為你收集整理的并发数据结构-1.1 并发的数据结构的设计的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Maven的Settings.xml配置
- 下一篇: Palo Alto Networks漏洞