可重入函式

可重入函式

可重入函式主要用於多任務環境中,一個可重入的函式簡單來說就是可以被中斷的函式,也就是說,可以在這個函式執行的任何時刻中斷它,轉入OS調度下去執行另外一段代碼,而返回控制時不會出現什麼錯誤;而不可重入的函式由於使用了一些系統資源,比如全局變數區,中斷向量表等,所以它如果被中斷的話,可能會出現問題,這類函式是不能運行在多任務環境下的。

基本介紹

  • 中文名:可重入函式
  • 外文名:Reentrant Function
  • 用於:多任務環境
  • 釋義:可以被中斷的函式
  • 相關:不可重入函式
簡介,注意事項,示例,與執行緒安全的關係,不可重入,

簡介

可重入函式也可以這樣理解,重入即表示重複進入,首先它意味著這個函式可以被中斷,其次意味著它除了使用自己棧上的變數以外不依賴於任何環境(包括static),這樣的函式就是purecode(純代碼)可重入,可以允許有多個該函式的副本在運行,由於它們使用的是分離的棧,所以不會互相干擾。如果確實需要訪問全局變數(包括static),一定要注意實施互斥手段。可重入函式在並行運行環境中非常重要,但是一般要為訪問全局變數付出一些性能代價。

注意事項

編寫可重入函式時,若使用全局變數,則應通過關中斷、信號量(即P、V操作)等手段對其加以保護。
若對所使用的全局變數不加以保護,則此函式就不具有可重入性,即當多個執行緒調用此函式時,很有可能使有關全局變數變為不可知狀態。

示例

假設Exam是int型全局變數,函式Square_Exam返回Exam平方值。那么如下函式不具有可重入性。
unsigned int example(int para){    unsigned int temp;    Exam = para; // (**)    temp = Square_Exam();    return temp;}
此函式若被多個進程調用的話,其結果可能是未知的,因為當(**)語句剛執行完後,另外一個使用本函式的進程可能正好被激活,那么當新激活的進程執行到此函式時,將使Exam賦予另一個不同的para值,所以當控制重新回到“temp = Square_Exam( )”後,計算出的temp很可能不是預想中的結果。此函式應如下改進。
unsigned int example( int para ){unsigned int temp;[申請信號量操作] //(1)Exam = para;temp = Square_Exam( );[釋放信號量操作]return temp;}
若申請不到“信號量”,說明另外的進程正處於給Exam賦值並計算其平方過程中(即正在使用此信號),本進程必須等待其釋放信號後,才可繼續執行。若申請到信號,則可繼續執行,但其它進程必須等待本進程釋放信號量後,才能再使用本信號。
保證函式的可重入性的方法:在寫函式時候儘量使用局部變數(例如暫存器、堆疊中的變數),對於要使用的全局變數要加以保護(如採取關中斷、信號量等方法),這樣構成的函式就一定是一個可重入的函式。
VxWorks中採取的可重入的技術有:
* 動態堆疊變數(各子函式有自己獨立的堆疊空間)
* 受保護的全局變數和靜態變數
* 任務變數

與執行緒安全的關係

可重入與執行緒安全兩個概念都關係到函式處理資源的方式。但是,他們有重大區別:
  • 可重入概念會影響函式的外部接口,而執行緒安全只關心函式的實現。
  • 大多數情況下,要將不可重入函式改為可重入的,需要修改函式接口,使得所有的數據都通過函式的調用者提供。
  • 要將非執行緒安全的函式改為執行緒安全的,則只需要修改函式的實現部分。一般通過加入同步機制以保護共享的資源,使之不會被幾個執行緒同時訪問。
作業系統背景與CPU調度策略:
  • 可重入是在單執行緒作業系統背景下,重入的函式或者子程式,按照後進先出的線性序依次執行完畢。
  • 多執行緒執行的函式或子程式,各個執行緒的執行時機是由作業系統調度,不可預期的,但是該函式的每個執行執行緒都會不時的獲得CPU的時間片,不斷向前推進執行進度。
可重入函式未必是執行緒安全的;執行緒安全函式未必是可重入的。
  • 例如,一個函式打開某個檔案並讀入數據。這個函式是可重入的,因為它的多個實例同時執行不會造成衝突;但它不是執行緒安全的,因為在它讀入檔案時可能有別的執行緒正在修改該檔案,為了執行緒安全必須對檔案加“同步鎖”。
  • 另一個例子,函式在它的函式體內部訪問共享資源使用了加鎖、解鎖操作,所以它是執行緒安全的,但是卻不可重入。因為若該函式一個實例運行到已經執行加鎖但未執行解鎖時被停下來,系統又啟動該函式的另外一個實例,則新的實例在加鎖處將轉入等待。如果該函式是一個中斷處理服務,在中斷處理時又發生新的中斷將導致資源死鎖。fprintf函式就是執行緒安全但不可重入。

不可重入

實時系統的設計中,經常會出現多個任務調用同一個函式的情況。如果這個函式被設計成為不可重入的函式的話,那么不同任務調用這個函式時可能修改其他任務用到的數據,從而導致不可預料的後果。那么什麼是可重入函式呢?所謂可重入函式是指一個可以被多個任務調用的函式(過程),任務在調用時不必擔心數據是否會出錯。不可重入函式在實時系統設計中被視為不安全函式。
滿足下列條件的函式多數是不可重入的:
1) 函式體內使用了靜態的數據結構;
2) 函式體內調用了malloc()或者free()函式;
3) 函式體內調用了標準I/O函式。
下面舉例加以說明。
A. 可重入函式
void strcpy(char *lpszDest, char *lpszSrc) {while(*lpszDest++=*lpszSrc++);*dest=0;}
B. 不可重入函式1
char cTemp;//全局變數void SwapChar1(char *lpcX, char *lpcY) {cTemp=*lpcX;*lpcX=*lpcY;lpcY=cTemp;//訪問了全局變數}
C. 不可重入函式2
void SwapChar2(char *lpcX,char *lpcY) {static char cTemp;//靜態局部變數cTemp=*lpcX;*lpcX=*lpcY;lpcY=cTemp;//使用了靜態局部變數}

相關詞條

熱門詞條

聯絡我們