C語言函數重入


C語言函數重入

  • 可重入函數:可以被中斷的函數,即這個函數執行時,可以中斷其執行,可以由一個或多個任務並發使用,而不比擔心數據錯誤。
  • 不可重入函數(不安全函數)
  1. 不能運行在多任務環境下,除非能保證互斥(使用信號量/代碼的關鍵部分禁用中斷)
  2. 是由於使用了未受保護的系統資源,如全局變量區,中斷向量表等。

 

可重入函數:

  1. 沒有靜態數據結構
  2. 不返回指向靜態數據的指針
  3. 所有函數數據由函數的調用者提供
  4. 使用auto變量,或通過全局變量的拷貝來保護全局變量
  5. 若必須訪問全局變量,則利用互斥信號保護
  6. 不調用不可重入函數

 

不可重入函數有:

如果一個函數在重入條件下使用了未受保護的共享的資源,那么它是不可重入的。 

  1. 函數中使用了靜態變量,無論是全局靜態變量還是局部靜態變量。 
  2. 函數返回靜態變量
  3. 函數中調用了不可重入函數
  4. 函數體內使用了靜態的數據結構
  5. 函數體內調用了malloc()或者free()函數
  6. 函數體內調用了其他標准I/O函數
  7. 函數是singleton中的成員函數,而且使用了不使用線程獨立存儲的成員變量

 

不可重入函數改寫成可重入函數:

1、不使用全局變量

2、在和硬件發生交互時,可能會發生中斷時,先關閉中斷(有些系列叫做“進入/退出核心”或者用OS_ENTER_KERNAL/OS_EXIT_KERNAL來描述,這是臨界區保護)

3、不調用不可重入函數

4、謹慎使用堆棧,最好在使用前OS_ENTER_KERNAL

 

中斷是嵌入式系統中重要的組成部分,這導致了很多編譯開發商提供一種擴展—讓標准C支持中斷。中斷服務子程序ISR

__interrupt double compute_area (double radius)  
{ 
    double area = PI * radius * radius; 
    printf("\nArea = %f", area); 
    return area; 
} 

錯誤:

1、ISR沒有返回值

如果它有返回值,返回給誰,某種中斷源產生中斷,系統使用ISR進行處理。ISR是鏈接在某一個中斷源上的,而中斷源的產生是隨機的,所以ISR並沒有一個固定的調用者,也沒有固定的返回地址,所以返回值沒有用。

2、ISR不能傳遞參數

3、在許多編譯器/處理器中,浮點數是不可重入的。有些不允許在ISR中做浮點運算。

4、ISR應該短、有效率的,做浮點數不明智。

5、printf是不可重入函數。

 

解釋:

1、浮點數:一般浮點運算都是由專門的硬件來完成,舉個例子假設有個硬件寄存器名字叫做FLOAT,用來計算和存放浮點數的中間運算結果
假設有這么個函數

void fun()
{
//...這個函數對FLOAT寄存器進行操作
}

假如第一次執行,有個對浮點數操作運算的結果臨時存在FLOAT寄存器中,而就在這時被中斷了,而中斷函數或者另一個進程也調用fun函數,這時第二次調用的fun函數在執行的過程中就會破壞第一次FLOAT寄存器中的結果,這樣當返回到第一次fun函數的時候,結果就不正確了。

 

2、printf函數

引用全局變量stdout,這是標准輸入輸出流的一個對象

malloc --------全局內存分配表
free    --------全局內存分配表

unix里面通常都有加上_r后綴的同名可重入函數版本。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM