在嵌入式裸機(jī)時代,也就是無OS時代,我們在裸機(jī)環(huán)境下編寫C語言程序非常簡單,實(shí)現(xiàn)一個函數(shù),然后將函數(shù)接口API提供給其它模塊調(diào)用就可以了。比如下面的函數(shù),我們實(shí)現(xiàn)一個sum函數(shù),用來求兩個數(shù)的和:
但是在一個運(yùn)行OS的多任務(wù)環(huán)境中,我們在編寫sum函數(shù)時就要注意一些細(xì)節(jié)了:我們編寫的sum函數(shù)可能會被多個任務(wù)調(diào)用,而且可能在sum函數(shù)執(zhí)行的過程被打斷,接著在另一個任務(wù)中再次調(diào)用sum函數(shù)。而在上面的sum函數(shù)實(shí)現(xiàn)中,我們定義了一個靜態(tài)變量sum用來保存兩個數(shù)相加的臨時結(jié)果,靜態(tài)變量是保存到數(shù)據(jù)段中的,大家可以想一想,在一個任務(wù)A中正在執(zhí)行sum(1,2)函數(shù)中的第4行,此時任務(wù)被打斷掛起,接著運(yùn)行任務(wù)B,在任務(wù)B中接著執(zhí)行sum(10,20)函數(shù),執(zhí)行結(jié)束后接著運(yùn)行任務(wù)A,A獲得CPU控制權(quán)后繼續(xù)運(yùn)行sum(1,2)的第5行,此時sum(1,2)的返回結(jié)果就變成了30,而不是正確結(jié)果3。
在一個多任務(wù)環(huán)境中,如果一個函數(shù)可以重復(fù)并發(fā)調(diào)用,而且多次調(diào)用并不會影響函數(shù)的運(yùn)行結(jié)果,那么這個函數(shù)是可重入的,我們稱這個函數(shù)為:可重入函數(shù)。在上面的sum函數(shù)實(shí)現(xiàn)中,當(dāng)其被多次并發(fā)調(diào)用時,函數(shù)的運(yùn)行結(jié)果并不確定,我們稱其為不可重入函數(shù)。
我們?nèi)绾稳ヅ卸ㄒ粋€函數(shù)是可重入的,還是不可重入的呢?很簡單,當(dāng)一個函數(shù)滿足下面任一條件,那么這個函數(shù)就是不可重入函數(shù)。
- 函數(shù)內(nèi)部使用了全局變量
- 函數(shù)內(nèi)部使用了靜態(tài)局部變量
- 函數(shù)返回值為全局變量或靜態(tài)變量
- 函數(shù)內(nèi)部使用了malloc/free函數(shù)
- 函數(shù)北部使用了標(biāo)準(zhǔn)I/O函數(shù)
- 函數(shù)內(nèi)部調(diào)用其它不可重入函數(shù)
不可重入函數(shù)在一個多任務(wù)環(huán)境中不能被多次并發(fā)調(diào)用,如果一個函數(shù)可能被多次調(diào)用,那么我們設(shè)計(jì)這個函數(shù)時盡量要將其設(shè)計(jì)為可重入函數(shù)。
- 不使用/返回靜態(tài)變量、全局變量
- 不使用標(biāo)準(zhǔn)I/O函數(shù)
- 不使用malloc/free函數(shù)
- 不調(diào)用不可重入函數(shù)
在函數(shù)設(shè)計(jì)時,只要注意上面的原則,那么我們就可以將一個函數(shù)設(shè)計(jì)為可重入函數(shù),可重入函數(shù)在多任務(wù)環(huán)境下可以被多次并發(fā)調(diào)用,是線程安全的,程序員可以放心大膽地調(diào)用。
理想很豐滿,現(xiàn)實(shí)很骨干。我們在編程中如果說不用malloc/free、全局變量,那是不現(xiàn)實(shí)的。只要我們使用了這些全局變量,靜態(tài)變量,那么函數(shù)就變成不可重入了,在多任務(wù)環(huán)境下使用這個函數(shù)就變得線程不安全了,那怎么辦呢?
方法還是有的,一個函數(shù)之所以變得不可重入,就是因?yàn)楹瘮?shù)內(nèi)有一些資源是全局共享的,在多任務(wù)環(huán)境下多次并發(fā)調(diào)用該函數(shù)時可能會破壞掉這些共享的全局資源。我們?nèi)绻堰@些資源在訪問的時候保護(hù)起來,不讓其它任務(wù)訪問(即互斥訪問),即同一時刻只允許一個進(jìn)程訪問就安全了。這些被保護(hù)的資源我們稱為臨界資源,訪問這些臨界資源的代碼段,我們稱之為臨界區(qū)。臨界區(qū)的訪問方式為互斥訪問,即同一時刻只允許一個進(jìn)程訪問。
臨界區(qū)的實(shí)現(xiàn)方式有很多種,不同的操作系統(tǒng)可能會提供不同的實(shí)現(xiàn)方式。我們可以通過下面的操作原語來實(shí)現(xiàn)一個臨界區(qū):
不同的操作系統(tǒng),具體的實(shí)現(xiàn)手段可能不一樣,常見的方法有:關(guān)中斷;實(shí)現(xiàn)互斥訪問,比如通過信號量、互斥量、自旋鎖等實(shí)現(xiàn),甚至原子操作等。比如在uc/os操作系統(tǒng)中,我們使用關(guān)中斷的方式來實(shí)現(xiàn)臨界區(qū),確保函數(shù)的線程安全。
而在linux/windows操作系統(tǒng)中,我們通常使用鎖機(jī)制來實(shí)現(xiàn)臨界區(qū):
在一個不可重入函數(shù)中,通過臨界區(qū)來實(shí)現(xiàn)共享全局資源的互斥訪問,那么在多任務(wù)環(huán)境下調(diào)用這個函數(shù)也就變得安全了,也就是說這個不可重入函數(shù)是線程安全的。
通過上面的分析,我們可以得出下面的結(jié)論:一個函數(shù)如果是可重入函數(shù),那么這個函數(shù)是線程安全的,其它進(jìn)程線程都可以對這個函數(shù)并發(fā)訪問,并不會影響函數(shù)的運(yùn)行結(jié)果。如果一個函數(shù)是不可重入函數(shù),我們通過臨界區(qū)設(shè)計(jì)對共享全局資源進(jìn)行互斥訪問,也可以讓這個函數(shù)變得線程安全,其它進(jìn)程線程也可以放心調(diào)用。由此,我們得出線程安全與可重入之間的關(guān)系如下:
也就是說,一個可重入函數(shù)肯定是線程安全的,而線程安全函數(shù)并不一定是可重入函數(shù),不可重入函數(shù)也有可能是線程安全的,比如我們常見的malloc函數(shù),就是不可重入函數(shù),但是是線程安全的,為什么呢?
通過《C語言嵌入式Linux高級編程》課程學(xué)習(xí),我們已經(jīng)知道,對于我們使用malloc/free申請釋放的內(nèi)存,glibc在用戶空間實(shí)現(xiàn)了一個內(nèi)存管理器,將各個大小的內(nèi)存塊鏈成多個全局鏈表進(jìn)行管理。
當(dāng)我們使用malloc/free申請釋放內(nèi)存時,如果申請/釋放的內(nèi)存塊大小符合規(guī)定,一般都是直接對這些全局鏈表進(jìn)行操作、避免多次系統(tǒng)調(diào)用進(jìn)入內(nèi)核態(tài),減少系統(tǒng)開銷。因?yàn)閙alloc/free函數(shù)對全局鏈表進(jìn)行了操作,所以malloc/free是不可重入函數(shù)。在訪問這些全局鏈表時,我們需要通過鎖機(jī)制加以保護(hù),每次malloc/free操作全局鏈表時,其它地方就被互斥訪問了,只有當(dāng)malloc/free操作全局鏈表完成退出,其它地方的malloc/free才能對這個全局鏈表進(jìn)行訪問。
通過上面的分析,我們可以看到:malloc/free雖然是不可重入函數(shù),但是通過加鎖對共享全局資源的互斥訪問,也就變得線程安全了,在多任務(wù)環(huán)境下,每個進(jìn)程都可以放心大膽地調(diào)用它:因?yàn)閙alloc雖然是不可重入函數(shù),但它是線程安全的。
-
嵌入式
+關(guān)注
關(guān)注
5148文章
19643瀏覽量
316979 -
C語言
+關(guān)注
關(guān)注
180文章
7632瀏覽量
141423 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4379瀏覽量
64737
發(fā)布評論請先 登錄
Keil C51處理科重入函數(shù)問題的探討
調(diào)用非安全線程的dll的問題
我想問如果我異步調(diào)用可重入 參數(shù)是X80會怎么樣
用ERTM關(guān)閉全局中斷來實(shí)現(xiàn)函數(shù)的可重入性有什么附加影響?
可重入函數(shù)相關(guān)資料推薦
窗函數(shù)對FFT有什么影響?他們是什么關(guān)系?
Linux 多線程可重入函數(shù)
可重入函數(shù)與不可重入函數(shù)分析
51單片機(jī)的可重入函數(shù)有什么陷阱

可重入和不可重入函數(shù)的詳細(xì)資料和應(yīng)用簡介

KEIL C51的重入函數(shù)的詳細(xì)資料講解

Linux中的可重入、異步信號安全和線程安全

為什么中斷處理函數(shù)不能直接調(diào)用不可重入函數(shù)
"可重入"和"線程安全"是兩個概念 千萬不要搞混了

CPU的核心數(shù)和線程數(shù)有什么關(guān)系

評論