可重入函數

## 可重入函數

### 可重入性的理解

若一個程序或子程序可以安全的被并行執行,則稱其為可重入的;即當該子程序正在運行時,可以再次進入并執行它。若一個函數是可重入的,則該函數必須滿足一下必要條件:

1. 不能含有靜態(全局)非常量數據。

2. 不能返回靜態(全局)非常量數據的地址。

3. 只能處理由調用者提供的數據。作為可重入函數的輸入參數,只能由調用者提供,而且所提供的輸入數據必須滿足上面兩點要求

4. 不能依賴于單實例模式資源的鎖。

5. 不能調用不可重入的函數。

6. 函數內部,盡量不能用 malloc 和 free 之類的方法進行內存分配和釋放,如果使用,一般情況下會造成該函數的不可重入.

可重入函數主要用于多任務環境中。可重入的函數必須滿足以下三個條件:

(1)可以在執行的過程中可以被打斷;

(2)被打斷之后,在該函數一次調用執行完之前,可以再次被調用(或進入,reentered)。

(3)再次調用執行完之后,被打斷的上次調用可以繼續恢復執行,并正確執行。

### 不可重入函數的示例

如果一個函數只有調用者提供的非靜態變量參數,并且函數中只依賴自己棧上的環境,也沒有調用其他的不可重入函數,那么他就一定是可重入的.這樣的函數就是purecode(純代碼)可重入,可以允許有該函數的多個副本在運行,由于它們使用的是分離的棧,所以不會互相干擾。如果確實需要訪問全局變量(包括 static),一定要注意實施互斥手段。可重入函數在并行運行環境中非常重要,但是一般要為訪問全局變量付出一些性能代價。

編寫可重入函數時,若使用全局變量,則應通過關中斷、信號量(即P、V操作)等手段對其加以保護。

說明:若對所使用的全局變量不加以保護,則此函數就不具有可重入性,即當多個進程調用此函數時,很有可能使有關全局變量變為不可知狀態。

```cpp

int Exam = 0;

unsigned int example( int para )

{

unsigned int temp;

Exam = para; // (**)

temp = Square_Exam( );

return temp;

}

```

此函數若被多個進程調用的話,其結果可能是未知的,因為當(**)語句剛執行完后,另外一個使用本函數的進程可能正好被激活,那么當新激活的進程執行到此函數時,將使 Exam 賦與另一個不同的 para 值,所以當控制重新回到 “temp = Square_Exam( )” 后,計算出的temp很可能不是預想中的結果。此函數應如下改進。

```cpp

view plaincopy在CODE上查看代碼片派生到我的代碼片

int Exam = 0;

unsigned int example( int para )

{

unsigned int temp;

[申請信號量操作] //(1)? 加鎖

Exam = para;

temp = Square_Exam( );

[釋放信號量操作] //? ? 解鎖

return temp;

}

```

申請不到“信號量”,說明另外的進程正處于給 Exam賦值并計算其平方過程中(即正在使用此信號),本進程必須等待其釋放信號后,才可繼續執行。若申請到信號,則可繼續執行,但其它進程必須等待本進程釋放信號量后,才能再使用本信號。

保證函數的可重入性的方法:

1. 在寫函數時候盡量使用局部變量(例如寄存器、堆棧中的變量);

2. 對于要使用的全局變量要加以保護(如采取關中斷、信號量等互斥方法),這樣構成的函數就一定是一個可重入的函數。

滿足下列條件的函數多數是不可重入(不安全)的:

1. 函數體內使用了靜態的數據結構;

2. 函數體內調用了malloc() 或者 free() 函數;

3. 函數體內調用了標準 I/O 函數。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容