中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

范縣網(wǎng)站建設(shè)公司精準(zhǔn)營銷通俗來說是什么

范縣網(wǎng)站建設(shè)公司,精準(zhǔn)營銷通俗來說是什么,最便宜的購物軟件排名,吉首企業(yè)網(wǎng)站建設(shè)價(jià)格指令亂序和線程安全 先來看什么是指令亂序問題以及為什么有指令亂序。程序的代碼執(zhí)行順序有可能被編譯器或CPU根據(jù)某種策略打亂指令執(zhí)行順序,目的是提升程序的執(zhí)行性能,讓程序的執(zhí)行盡可能并行,這就是所謂指令亂序問題。理解指令亂序的策略是…

指令亂序和線程安全

先來看什么是指令亂序問題以及為什么有指令亂序。程序的代碼執(zhí)行順序有可能被編譯器或CPU根據(jù)某種策略打亂指令執(zhí)行順序,目的是提升程序的執(zhí)行性能,讓程序的執(zhí)行盡可能并行,這就是所謂指令亂序問題。理解指令亂序的策略是很重要的,因?yàn)檐浖O(shè)計(jì)人員可以在正確的位置告訴編譯器或CPU哪里可以允許指令亂序,哪里不能接受指令亂序,從而在保證軟件正確性的同時(shí)允許編譯或執(zhí)行層面的性能優(yōu)化。

指令亂序問題需要分為三個(gè)層次:

  • 第1層是多線程編程中的業(yè)務(wù)邏輯層面的函數(shù)可重入性和線程安全問題;
  • 第2層是編譯器編譯優(yōu)化造成的指令亂序;
  • 第3層是CPU亂序執(zhí)行指令的問題。

我們?cè)谟懻揅PU指令亂序問題和編譯器指令亂序問題之前,先來簡要討論一下可重入函數(shù)與線程安全相關(guān)的問題。

可重入函數(shù)與線程安全

線程的基本概念

線程(thread)是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位。它包含在進(jìn)程之中,是進(jìn)程中的實(shí)際運(yùn)作單位。一個(gè)線程指的是進(jìn)程中一個(gè)單一順序的控制流,一個(gè)進(jìn)程中可以并發(fā)多個(gè)線程,每條線程并行執(zhí)行不同的任務(wù)。一般默認(rèn)一個(gè)進(jìn)程中只包含一個(gè)線程。

操作系統(tǒng)中的線程概念也被延伸到CPU硬件上,多線程CPU就是在一個(gè)CPU上支持同時(shí)運(yùn)行多個(gè)指令流,而多核CPU就是在一塊芯片上集成了多個(gè)CPU核,比如4核8線程CPU芯片就是在集成了4個(gè)CPU核,每個(gè)CPU核上支持2個(gè)線程。

有了多核多線程CPU,操作系統(tǒng)就可以讓不同進(jìn)程運(yùn)行在不同的CPU核的不同線程上,從而大大減少進(jìn)程調(diào)度進(jìn)程切換的資源消耗。傳統(tǒng)上操作系統(tǒng)工作在單核單線程CPU上是通過分時(shí)共享CPU來模擬出多個(gè)指令執(zhí)行流,從而實(shí)現(xiàn)多進(jìn)程和多線程的。

函數(shù)調(diào)用堆??蚣?/h2>

借助函數(shù)調(diào)用堆??梢詫⑽覀儗懙暮瘮?shù)調(diào)用代碼整理成一個(gè)順序執(zhí)行的指令流,也就是一個(gè)線程,每一個(gè)線程都有一個(gè)獨(dú)自擁有的函數(shù)調(diào)用堆??臻g,其中函數(shù)參數(shù)和局部變量都存儲(chǔ)在函數(shù)調(diào)用堆??臻g中,因此函數(shù)參數(shù)和局部變量也是線程獨(dú)自擁有的。除了函數(shù)調(diào)用堆??臻g,同一個(gè)進(jìn)程的多個(gè)線程是共享其他進(jìn)程資源的,比如全局變量是多個(gè)線程共享的。

可重入函數(shù)

可重入(reentrant)函數(shù)可以由多于一個(gè)任務(wù)并發(fā)使用,而不必?fù)?dān)心數(shù)據(jù)錯(cuò)誤。相反,不可重入(non-reentrant)函數(shù)不能由超過一個(gè)任務(wù)所共享,除非能確保函數(shù)的互斥(或者使用信號(hào)量,或者在代碼的關(guān)鍵部分禁用中斷)??芍厝牒瘮?shù)可以在任意時(shí)刻被中斷,稍后再繼續(xù)運(yùn)行,不會(huì)丟失數(shù)據(jù)??芍厝牒瘮?shù)要么使用局部變量,要么在使用全局變量時(shí)保護(hù)自己的數(shù)據(jù)。

int g = 0;
int function()
{g++; /* switch to another thread */printf("%d", g);
}int function2(int a)
{a++;printf("%d", a); 
}

function()函數(shù)為不可重入函數(shù),其中的變量g為全局變量,多個(gè)線程同時(shí)執(zhí)行function函數(shù)時(shí)會(huì)出現(xiàn)變量g的值未按照預(yù)想的結(jié)果輸出的情況,function2(int a)為可重入函數(shù),function2函數(shù)中的變量a是對(duì)傳入的實(shí)參變量的拷貝,并不影響原來傳入的變量。

可重入函數(shù)的基本要求

(1)不為連續(xù)的調(diào)用持有靜態(tài)數(shù)據(jù); ?? ?

(2)不返回指向靜態(tài)數(shù)據(jù)的指針; ?? ?

(3)所有數(shù)據(jù)都由函數(shù)的調(diào)用者提供; ?? ?

(4)使用局部變量,或者通過制作全局?jǐn)?shù)據(jù)的局部變量拷貝來保護(hù)全局?jǐn)?shù)據(jù); ?

(5)使用靜態(tài)數(shù)據(jù)或全局變量時(shí)做周密的并行時(shí)序分析,通過臨界區(qū)互斥避免臨界區(qū)沖突; ?? ?

(6)絕不調(diào)用任何不可重入函數(shù)。

什么是線程安全?

如果你的代碼所在的進(jìn)程中有多個(gè)線程在同時(shí)運(yùn)行,而這些線程可能會(huì)同時(shí)運(yùn)行這段代碼。如果每次運(yùn)行結(jié)果和單線程運(yùn)行的結(jié)果是一樣的,而且其他的變量的值也和預(yù)期的是一樣的,就是線程安全的。

線程安全問題都是由全局變量及靜態(tài)變量引起的。若每個(gè)線程中對(duì)全局變量、靜態(tài)變量只有讀操作,而無寫操作,一般來說,這個(gè)全局變量是線程安全的;若有多個(gè)線程同時(shí)執(zhí)行讀寫操作,一般都需要考慮線程同步,否則就可能影響線程安全。

函數(shù)的可重入性與線程安全之間的關(guān)系

可重入的函數(shù)不一定是線程安全的,可能是線程安全的也可能不是線程安全的;同一個(gè)可重入的函數(shù)在多個(gè)線程中并發(fā)使用時(shí)是線程安全的,但不同的可重入函數(shù)(共享全局變量及靜態(tài)變量)在多個(gè)線程中并發(fā)使用時(shí)會(huì)有線程安全問題;不可重入的函數(shù)一定不是線程安全的。

int g = 0;
int plus()
{pthread_mutex_lock(&gplusplus);g++; /* switch to another thread */printf("%d", g);pthread_mutex_unlock(&gplusplus);
}
int minus()
{pthread_mutex_lock(&gminusminus);g--; /* switch to another thread */printf("%d", g);pthread_mutex_unlock(&gminusminus);
}

上述兩個(gè)函數(shù)plus() 和 minus() 經(jīng)過加鎖處理之后均稱為可重入函數(shù),但由于使用的是兩個(gè)不同的互斥鎖,所以在并發(fā)執(zhí)行時(shí)會(huì)出現(xiàn)g的值與預(yù)期不一致的現(xiàn)象。故說明可重入函數(shù)不一定是線程安全的。

線程安全和指令亂序

我們這里討論可重入函數(shù)與線程安全本質(zhì)上也是指令亂序執(zhí)行問題,指令亂序問題本質(zhì)上也是線程安全問題,編譯器編譯優(yōu)化或CPU指令亂序執(zhí)行所引發(fā)的程序正確性問題盡管所處的層次不同但本質(zhì)上與此相似,接下來我們分別討論一下CPU指令亂序問題和編譯器指令亂序問題。

CPU的流水線技術(shù)能夠讓指令的執(zhí)行盡可能地并行起來,但是如果兩條指令前后存在依賴關(guān)系,比如數(shù)據(jù)依賴、控制依賴等,此時(shí)后一條指令就必需等到前一條指令完成后才能開始執(zhí)行。為了提高流水線的運(yùn)行效率,CPU會(huì)對(duì)無依賴的前后指令做適當(dāng)?shù)膩y序和調(diào)整,對(duì)控制依賴的指令做分支預(yù)測,對(duì)內(nèi)存訪問等耗時(shí)操作提前預(yù)先處理等,這些都會(huì)導(dǎo)致指令亂序執(zhí)行。

編譯器很重要的一項(xiàng)工作就是優(yōu)化我們的代碼以提高性能。這包括在不改變程序正確性的條件下重新排列指令,也就是編譯器指令亂序問題。

CPU指令執(zhí)行的順序一致性

為了提高流水線的運(yùn)行效率,CPU會(huì)對(duì)無依賴的前后指令做適當(dāng)?shù)膩y序和調(diào)整,對(duì)控制依賴的指令做分支預(yù)測,對(duì)內(nèi)存訪問等耗時(shí)操作提前預(yù)先處理等,這些都會(huì)導(dǎo)致指令亂序執(zhí)行。

但是我們編程時(shí)一般理解代碼在CPU上的執(zhí)行順序和代碼的邏輯順序是一致的呀?這有點(diǎn)讓人困惑。從單核單線程CPU的角度來看,指令在CPU內(nèi)部可能是亂序執(zhí)行的,但是對(duì)外表現(xiàn)卻是順序執(zhí)行的。因?yàn)?strong>指令集架構(gòu)(ISA)中的指令寄存器作為CPU的對(duì)外接口,CPU只需要把內(nèi)部真實(shí)的物理寄存器按照指令的執(zhí)行順序,順序映射到ISA寄存器上,也就是CPU只要將結(jié)果順序地提交到ISA寄存器,就可以保證順序一致性(Sequential consistency)。

多核CPU上指令亂序執(zhí)行

顯然在單核單線程CPU上指令亂序問題被指令集架構(gòu)所屏蔽,但是在多核多線程CPU上依然存在指令亂序執(zhí)行的可能性。比如存在變量x = 0,CPU0上執(zhí)行寫入操作x = 1。接著在CPU1上,執(zhí)行讀取操作依然得到x = 0,這在X86和ARM多核CPU上都是可能出現(xiàn)的。原因是如圖所示CPU核和Cache以及內(nèi)存之間,存在著Store Buffer,當(dāng)x = 1執(zhí)行寫入操作成功后,修改只存在于Store Buffer中,并未寫到cache以及內(nèi)存上,因此CPU1讀取不到最新的x值。除了Store Buffer,而且還可能會(huì)有Invalidate Queue,導(dǎo)致CPU1讀不到最新的x值。為了能夠保證多核之間的修改可見性,我們?cè)趯懗绦虻臅r(shí)候需要加上內(nèi)存屏障,例如X86上的mfence指令。

ARM64 CPU指令亂序

對(duì)于ARM64架構(gòu)的CPU來說,編程就變得危險(xiǎn)多了。除了存在數(shù)據(jù)依賴、控制依賴和地址依賴等不能被亂序執(zhí)行外,其余指令間都有可能存在亂序執(zhí)行。ARM64上沒有依賴關(guān)系的讀后讀、寫后寫、讀后寫和寫后讀都是可以亂序執(zhí)行的。ARM64架構(gòu)下Store Buffer并不是FIFO的,而且還可能存在Invalidate Queue,這讓并發(fā)編程變得困難重重。總之ARM64是弱內(nèi)存序模型因?yàn)榫喼噶罴言L存指令和運(yùn)算指令分開了,為了性能允許幾乎所有的指令亂序,但前提是不影響程序的正確性。因此ARM64架構(gòu)的指令亂序問題需要引入不同類型的barrier來保證程序的正確性。

需要特別指出的是ARM64允許指令亂序執(zhí)行是出于性能的考慮,這是架構(gòu)特性,不是漏洞。但是指令亂序的影響卻給系統(tǒng)可靠性帶來了風(fēng)險(xiǎn),驅(qū)動(dòng)模塊、基礎(chǔ)軟件和應(yīng)用軟件都要做排查和設(shè)計(jì)優(yōu)化。

高級(jí)語言定義了邏輯關(guān)系,邏輯關(guān)系與應(yīng)用程序的業(yè)務(wù)邏輯有關(guān);編譯器將內(nèi)含邏輯關(guān)系的高級(jí)語言代碼翻譯成機(jī)器語言或匯編語言,其中就定義了數(shù)據(jù)依賴、控制依賴和地址依賴等依賴關(guān)系;ARMv8架構(gòu)定義了內(nèi)存模型以及實(shí)現(xiàn)處理這些依賴關(guān)系的機(jī)器語言指令,從而防止有依賴的指令亂序執(zhí)行影響程序正確性。

顯然CPU指令亂序與硬件內(nèi)存模型及防止指令亂序的機(jī)器語言指令內(nèi)部實(shí)現(xiàn)緊密相關(guān),這些需要深入到處理器微架構(gòu)深處才能一探究竟,與我們專注于Linux內(nèi)核的目標(biāo)不符,這里不再深入探討它。但是我們需要清楚的一點(diǎn)是,CPU僅能看到機(jī)器指令或匯編指令序列中的數(shù)據(jù)依賴、控制依賴和地址依賴等依賴關(guān)系,并不能理解高級(jí)語言中定義的邏輯關(guān)系,因此CPU指令亂序執(zhí)行和編譯優(yōu)化指令亂序都可能會(huì)破壞高級(jí)語言中定義的邏輯關(guān)系,這是我們學(xué)習(xí)指令亂序問題的原因。

編譯器指令亂序問題

編譯器很重要的一項(xiàng)工作就是優(yōu)化我們的代碼以提高性能。這包括在不改變程序正確性的條件下重新排列指令,也就是編譯器指令亂序問題。

因?yàn)榫幾g器不知道什么樣的代碼需要線程安全,所以編譯器假設(shè)代碼都是單線程執(zhí)行的,也就是編譯器對(duì)函數(shù)的可重入問題是沒有感知的,因此編譯器進(jìn)行指令重排優(yōu)化只能保證是單線程安全。因此當(dāng)多線程應(yīng)用程序的邏輯關(guān)系在編譯器重新排序指令的時(shí)候可能影響程序正確性時(shí),除非你顯式告訴編譯器,我不需要重排指令順序,否則編譯器可能會(huì)在優(yōu)化指令順序時(shí)影響程序的正確性。這一部分我們一起探究編譯器編譯優(yōu)化相關(guān)的指令亂序問題。

編譯器屏障

在閱讀Linux內(nèi)核源代碼時(shí),會(huì)看到額外插入的匯編指令如下,是告訴編譯器不要優(yōu)化指令順序。如下代碼摘自Linux內(nèi)核源代碼include/linux/compiler-gcc.h。

#define barrier() __asm__ __volatile__("": : :"memory")

如上代碼定義的宏barrier()就是常說的編譯器屏障(compiler barriers),它的主要用途就是告訴編譯器不要優(yōu)化重排指令順序。為了說明這個(gè)問題我們用C語言代碼及對(duì)應(yīng)的ARM64匯編代碼簡要說明指令亂序造成的問題及編譯器屏障的作用。

編譯器優(yōu)化造成指令亂序問題

編譯器的主要工作就是將高級(jí)語言源代碼翻譯成機(jī)器指令,當(dāng)然翻譯的過程中編譯器還會(huì)進(jìn)行編譯優(yōu)化以提高代碼的執(zhí)行效率。編譯優(yōu)化主要就是在不影響程序正確性的情況下對(duì)機(jī)器指令順序重排從而統(tǒng)籌調(diào)度CPU資源改善程序性能,但是對(duì)于多線程應(yīng)用程序編譯器并不能理解程序的并發(fā)執(zhí)行邏輯,很可能會(huì)好心干壞事。為了說明編譯優(yōu)化指令亂序造成的問題,我們考慮下面的compiler_reordering.c文件中C語言函數(shù)function的代碼。

int flag, data;int function(void)
{data = data + 1;flag = 1;
} 

編譯時(shí)未開啟編譯優(yōu)化?

gcc -S compiler_reordering.c -o compiler_reordering.s
function:adrp	x0, :got:dataldr	x0, [x0, #:got_lo12:data]ldr	w0, [x0] 	// load data to w0add	w1, w0, 1 // w1 = w0 + 1adrp	x0, :got:dataldr	x0, [x0, #:got_lo12:data]str	w1, [x0]	// data = data + 1adrp	x0, :got:flagldr	x0, [x0, #:got_lo12:flag]mov	w1, 1		// w1 = 1str	w1, [x0]	// flag = 1nopret

編譯時(shí)開啟編譯優(yōu)化??

gcc -O2 -S compiler_reordering.c -o compiler_reordering_O2.s
function:adrp	x1, :got:dataadrp	x3, :got:flagmov	w4, 1		// w4 = 1ldr	x1, [x1, #:got_lo12:data]ldr	x3, [x3, #:got_lo12:flag]ldr	w2, [x1]	// load data to w2str	w4, [x3]	// flag = 1add	w2, w2, w4	// w2 = w2 + 1str	w2, [x1]	// data = data + 1ret

與上述C語言函數(shù)function中的代碼比較,這段優(yōu)化后的ARM64匯編代碼的執(zhí)行順序是不同的。C代碼中是先存儲(chǔ)了data的值,后存儲(chǔ)了flag的值,而優(yōu)化后的ARM64匯編代碼正好相反,先存儲(chǔ)了flag,后保存了data。

這就是編譯器指令亂序問題的典型范例。為什么編譯器會(huì)這么做呢?對(duì)于單線程來說,data和 flag的寫入順序,編譯器認(rèn)為沒有任何問題的。并且最終的結(jié)果data和flag的值也是正確的。

實(shí)際上這種編譯器指令亂序問題在大部分情況下是沒有問題的。但是在某些情況下可能會(huì)引入問題。例如我們使用的全局變量flag標(biāo)記共享數(shù)據(jù)data是否就緒。另外一個(gè)線程檢測到flag == 1就認(rèn)為data已經(jīng)就緒,而由于編譯器指令亂序,實(shí)際上data的值可能還沒有存入內(nèi)存。

下面我們加入內(nèi)存屏障,再來看看編譯后產(chǎn)生的匯編文件。?

#define barrier() __asm__ __volatile__("": : :"memory")int flag, data;int function(void)
{data = data + 1;barrier();flag = 1;
}
function:adrp	x0, :got:dataldr	x0, [x0, #:got_lo12:data]ldr	w1, [x0]		// load data to w1add	w1, w1, 1		// w1 = w1 + 1str	w1, [x0]		// data = data + 1adrp	x1, :got:flagmov	w2, 1			// w2 = 1ldr	x1, [x1, #:got_lo12:flag]str	w2, [x1]		// flag = 1ret

barrier就是編譯器提供的內(nèi)存屏障,作用是告訴編譯器內(nèi)存中的值已經(jīng)改變,之前對(duì)內(nèi)存的緩存(緩存到寄存器)都需要拋棄,barrier之后的內(nèi)存操作需要重新從內(nèi)存加載,而不能使用之前寄存器緩存的值。可以防止編譯器優(yōu)化barrier前后的內(nèi)存訪問順序。barrier就像是代碼中的一道不可逾越的屏障,barrier前的內(nèi)存讀寫操作不能跑到barrier后面;同樣barrier后面的內(nèi)存讀寫操作不能在barrier之前。


以上內(nèi)容為中科大軟件學(xué)院《高級(jí)軟件工程》課后總結(jié),感謝孟寧老師的傾心教授,老師講的太好啦(^_^)

參考資料:《代碼中的軟件工程》? ? 孟寧? 編著

http://www.risenshineclean.com/news/42614.html

相關(guān)文章:

  • vue可以做pc端網(wǎng)站嗎河南網(wǎng)站推廣
  • 旅游景區(qū)網(wǎng)站建設(shè)谷歌搜索指數(shù)查詢
  • 印刷網(wǎng)絡(luò)商城網(wǎng)站建設(shè)推廣新產(chǎn)品最好的方法
  • 信陽專業(yè)做網(wǎng)站公司客戶管理軟件
  • 網(wǎng)站制作軟件手機(jī)百度優(yōu)化軟件
  • 自己在家開網(wǎng)站做推廣百度優(yōu)化關(guān)鍵詞
  • 網(wǎng)站推介方案谷歌官方網(wǎng)站登錄入口
  • 單位網(wǎng)站開發(fā)合同泉州網(wǎng)站seo外包公司
  • 建設(shè)家具網(wǎng)站的目的及功能定位北京網(wǎng)絡(luò)營銷策劃公司
  • 選擇網(wǎng)站的關(guān)鍵詞cpu優(yōu)化軟件
  • wordpress備份網(wǎng)站南寧百度首頁優(yōu)化
  • 自己搭建云游戲服務(wù)器seo優(yōu)化推廣業(yè)務(wù)員招聘
  • 網(wǎng)站icp備案號(hào)查詢百度關(guān)鍵詞代做排名
  • 新公司網(wǎng)站建設(shè)百度平臺(tái)營銷收費(fèi)標(biāo)準(zhǔn)
  • 網(wǎng)站開發(fā)電商快速網(wǎng)站推廣優(yōu)化
  • 濰坊百度網(wǎng)站建設(shè)產(chǎn)品推廣圖片
  • 內(nèi)銷機(jī)械做哪個(gè)網(wǎng)站好開發(fā)新客戶的十大渠道
  • 沈陽建信建設(shè)工程有限公司位置seo關(guān)鍵詞排名網(wǎng)絡(luò)公司
  • 企業(yè)網(wǎng)站banner尺寸小紅書外鏈管家
  • wordpress短視頻模板紹興seo
  • 網(wǎng)站開發(fā)成本核算杭州seo公司哪家好
  • 網(wǎng)站模板 尋模板百度競價(jià)開戶費(fèi)用
  • 嬰幼兒網(wǎng)站模板鎮(zhèn)江百度推廣公司
  • 巨野網(wǎng)站建設(shè)百度云搜索引擎 百度網(wǎng)盤
  • 做網(wǎng)站想注冊(cè)商標(biāo)是哪一類百度公司總部在哪里
  • 專業(yè)制作公司網(wǎng)站公司百度一下首頁下載安裝桌面
  • 下載住小幫app看裝修seo排名優(yōu)化代理
  • 百度搜索網(wǎng)站怎么做策劃網(wǎng)絡(luò)營銷活動(dòng)
  • 校園網(wǎng)站開發(fā)背景淘寶seo關(guān)鍵詞的獲取方法有哪些
  • 織夢(mèng)網(wǎng)站+當(dāng)前位置限制寬度市場調(diào)研的內(nèi)容