歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> 關於Linux >> 簡介Linux中的可重入函數和不可重入函數

簡介Linux中的可重入函數和不可重入函數

日期:2017/3/3 16:24:04   编辑:關於Linux

可重入函數

可重入函數(即可以被中斷的函數)可以被一個以上的任務調用,而不擔心數據破壞。可重入函數在任何時候都可以被中斷,而一段時間之後又可以恢復運行,而相應的數據不會破壞或者丟失。

可重入函數使用的變量有兩種情況:

1.使用局部變量,變量保存在CPU寄存器中或者堆棧中;

2.使用全局變量,但是這時候要注意保護全局變量(防止任務中斷後被其它任務改變變量)。

void strcpy(*dest,*src)
{
    while(* dest++ = *src ++){;}
    *dest = NUL;
}

分析:上面的函數用於字符串復制,而參數是存放在堆棧中的,故而改函數可以被多任務調用,而不必擔心各個任務調用期間會互相破壞對方的指針。

基本上下面的函數都是不可重入的:

1.函數內使用了靜態的數據。

2.函數內使用了malloc()或者free()函數的。

3.函數內調用了標准的I/O函數的。

int temp;
 void swap(int *ex1,int *ex2)
{
    temp = *ex1; //(1)
    *ex1 = *ex2;
    *ex2 = temp;
}

分析:該函數中的全局變量temp是的函數變成了一個不可重入的函數,因為在多任務系統中,假如在任務1中調用swap函數,而程序執行到(1)處時被中斷,進而執行其它的任務2,而剛好任務2也調用了swap函數,則temp裡存的值則會被任務2改變。從而回到任務1被中斷處繼續執行的時候,temp裡存的值已經不再是原來存的temp值了,進而產生了錯誤。 常用的可重入函數的方法有:1.不要使用全局變量,防止別的代碼覆蓋這些變量的值。2.調用這類函數之前先關掉中斷,調用完之後馬上打開中斷。防止函數執行期間被中斷進入別的任務執行。3.使用信號量(互斥條件)。總之:要保證中斷是安全的

不可重入函數

在多任務系統下,中斷可能在任務執行的任何時間發生;如果一個函數的執行期間被中斷後,到重新恢復到斷點進行執行的過程中,函數所依賴的環境沒有發生改變,那麼這個函數就是可重入的,否則就不可重入。

在中斷前後不都要保存和恢復上下文嗎,怎麼會出現函數所依賴的環境發生改變了呢?

我們知道中斷時確實保存一些上下文,但是僅限於返回地址,cpu寄存器等之類的少量上下文,而函數內部使用的諸如全局或靜態變量,buffer等並不在保護之列,所以如果這些值在函數被中斷期間發生了改變,那麼當函數回到斷點繼續執行時,其結果就不可預料了。

滿足下面條件之一的多數是不可重入函數:

(1)使用了靜態數據結構;

(2)調用了malloc或free;

(3)調用了標准I/O函數;

(4)進行了浮點運算.

malloc/free是不可重入的,它們使用了全局變量來指向空閒區;標准I/O庫的很多實現都使用了全局數據結構; 許多的處理器/編譯器中,浮點一般都是不可重入的 (浮點運算大多使用協處理器或者軟件模擬來實現)。

在信號處理程序及多線程編程時,要特別注意。

考慮這種情況:

1) 信號處理程序A內外都調用了同一個不可重入函數B;B在執行期間被信號打斷,進入A (A中調用了B),完事之後返回B被中斷點繼續執行,這時B函數的環境可能改變,其結果就不可預料了。

2) 多線程共享進程內部的資源,如果兩個線程A,B調用同一個不可重入函數F,A線程進入F後,線程調度,切換到B,B也執行了F,那麼當再次切換到線程A時,其調用F的結果也是不可預料的。

在信號處理程序中即使調用可重入函數也有問題要注意。作為一個通用的規則,當在信號處理程序中調用可重

入函數時,應當在其前保存errno,並在其後恢復errno。(要了解經常被捕捉到的信號是SIGCHLD,其信號處理程序通常要調用一種wait函數,而各種wait函數都能改變errno。)

Copyright © Linux教程網 All Rights Reserved