## 可重入函數(shù)
### 可重入性的理解
若一個(gè)程序或子程序可以安全的被并行執(zhí)行,則稱其為可重入的捕透;即當(dāng)該子程序正在運(yùn)行時(shí)菇爪,可以再次進(jìn)入并執(zhí)行它。若一個(gè)函數(shù)是可重入的袋励,則該函數(shù)必須滿足一下必要條件:
1. 不能含有靜態(tài)(全局)非常量數(shù)據(jù)侥啤。
2. 不能返回靜態(tài)(全局)非常量數(shù)據(jù)的地址。
3. 只能處理由調(diào)用者提供的數(shù)據(jù)插龄。作為可重入函數(shù)的輸入?yún)?shù)愿棋,只能由調(diào)用者提供,而且所提供的輸入數(shù)據(jù)必須滿足上面兩點(diǎn)要求
4. 不能依賴于單實(shí)例模式資源的鎖均牢。
5. 不能調(diào)用不可重入的函數(shù)糠雨。
6. 函數(shù)內(nèi)部,盡量不能用 malloc 和 free 之類的方法進(jìn)行內(nèi)存分配和釋放徘跪,如果使用甘邀,一般情況下會(huì)造成該函數(shù)的不可重入.
可重入函數(shù)主要用于多任務(wù)環(huán)境中】迓可重入的函數(shù)必須滿足以下三個(gè)條件:
(1)可以在執(zhí)行的過程中可以被打斷松邪;
(2)被打斷之后,在該函數(shù)一次調(diào)用執(zhí)行完之前哨查,可以再次被調(diào)用(或進(jìn)入逗抑,reentered)。
(3)再次調(diào)用執(zhí)行完之后寒亥,被打斷的上次調(diào)用可以繼續(xù)恢復(fù)執(zhí)行邮府,并正確執(zhí)行。
### 不可重入函數(shù)的示例
如果一個(gè)函數(shù)只有調(diào)用者提供的非靜態(tài)變量參數(shù),并且函數(shù)中只依賴自己棧上的環(huán)境,也沒有調(diào)用其他的不可重入函數(shù),那么他就一定是可重入的.這樣的函數(shù)就是purecode(純代碼)可重入溉奕,可以允許有該函數(shù)的多個(gè)副本在運(yùn)行褂傀,由于它們使用的是分離的棧,所以不會(huì)互相干擾加勤。如果確實(shí)需要訪問全局變量(包括 static)仙辟,一定要注意實(shí)施互斥手段■罚可重入函數(shù)在并行運(yùn)行環(huán)境中非常重要叠国,但是一般要為訪問全局變量付出一些性能代價(jià)。
編寫可重入函數(shù)時(shí)戴尸,若使用全局變量粟焊,則應(yīng)通過關(guān)中斷、信號(hào)量(即P、V操作)等手段對(duì)其加以保護(hù)吆玖。
說明:若對(duì)所使用的全局變量不加以保護(hù)筒溃,則此函數(shù)就不具有可重入性,即當(dāng)多個(gè)進(jìn)程調(diào)用此函數(shù)時(shí)沾乘,很有可能使有關(guān)全局變量變?yōu)椴豢芍獱顟B(tài)怜奖。
```cpp
int Exam = 0;
unsigned int example( int para )
{
unsigned int temp;
Exam = para; // (**)
temp = Square_Exam( );
return temp;
}
```
此函數(shù)若被多個(gè)進(jìn)程調(diào)用的話,其結(jié)果可能是未知的翅阵,因?yàn)楫?dāng)(**)語句剛執(zhí)行完后歪玲,另外一個(gè)使用本函數(shù)的進(jìn)程可能正好被激活,那么當(dāng)新激活的進(jìn)程執(zhí)行到此函數(shù)時(shí)掷匠,將使 Exam 賦與另一個(gè)不同的 para 值滥崩,所以當(dāng)控制重新回到 “temp = Square_Exam( )” 后,計(jì)算出的temp很可能不是預(yù)想中的結(jié)果讹语。此函數(shù)應(yīng)如下改進(jìn)钙皮。
```cpp
view plaincopy在CODE上查看代碼片派生到我的代碼片
int Exam = 0;
unsigned int example( int para )
{
unsigned int temp;
[申請(qǐng)信號(hào)量操作] //(1)? 加鎖
Exam = para;
temp = Square_Exam( );
[釋放信號(hào)量操作] //? ? 解鎖
return temp;
}
```
申請(qǐng)不到“信號(hào)量”,說明另外的進(jìn)程正處于給 Exam賦值并計(jì)算其平方過程中(即正在使用此信號(hào))顽决,本進(jìn)程必須等待其釋放信號(hào)后短条,才可繼續(xù)執(zhí)行。若申請(qǐng)到信號(hào)才菠,則可繼續(xù)執(zhí)行茸时,但其它進(jìn)程必須等待本進(jìn)程釋放信號(hào)量后,才能再使用本信號(hào)赋访。
保證函數(shù)的可重入性的方法:
1. 在寫函數(shù)時(shí)候盡量使用局部變量(例如寄存器可都、堆棧中的變量);
2. 對(duì)于要使用的全局變量要加以保護(hù)(如采取關(guān)中斷蚓耽、信號(hào)量等互斥方法)渠牲,這樣構(gòu)成的函數(shù)就一定是一個(gè)可重入的函數(shù)。
滿足下列條件的函數(shù)多數(shù)是不可重入(不安全)的:
1. 函數(shù)體內(nèi)使用了靜態(tài)的數(shù)據(jù)結(jié)構(gòu)田晚;
2. 函數(shù)體內(nèi)調(diào)用了malloc() 或者 free() 函數(shù)嘱兼;
3. 函數(shù)體內(nèi)調(diào)用了標(biāo)準(zhǔn) I/O 函數(shù)国葬。