1. 程式人生 > >可重入函數與線程安全

可重入函數與線程安全

可重入函數 不可重入函數 線程安全

介紹:

一組並發線程運行在同一進程上下文中,每一個線程都有自己獨立的線程上下文,包括線程ID、棧、棧指針、程序計數器、條件碼和通用目的寄存器。每個線程和其他線程一起共享進程上下文的其他部分,包括整個用戶虛擬地址空間(由代碼段、讀/寫數據、堆以及所有共享庫的代碼和數據區組成)。線程也共享打開的文件集合。當存在共享資源的時候,對資源的訪問需要同步。這時候使用線程編寫程序的時候,需要編寫具有線程安全性屬性的函數。一個函數,當且僅當被多個並發線程反復調用時,能夠一直產生正確的結果,才能夠被稱為線程安全的,否則我們稱其為非線程安全的。


可重入的特點:

  1. 由於可重入函數多次調用不會出錯,所以不必擔心數據被破壞;

  2. 可重入函數在任何時候都可以被中斷,一段時間後又可以運行,相應的數據不會丟失;

  3. 可重入函數只使用局部變量,即保存在CPU寄存器或者堆棧中,使用全局變量要加以保護;


不可重入的特點:

  1. 使用malloc/free函數,malloc函數是用全局鏈表來管理堆棧的;

  2. 調用標準I/O庫函數,標準I/O庫的很多實現都以不可重入的方式使用全局數據結構;

  3. 可重入體內使用了靜態數據結構;

常見的不可重入函數有:

printf----引用了全局變量stdout

malloc---全局內存分配表

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


線程安全與可重入:

可重入的定義源自於單線程環境。在單線程環境中,一段代碼在執行中可能會被硬件中斷,並轉而調用中斷服務程序(ISR)。在這次調用中斷處理函數之前,有可能中斷處理函數已經在執行。因此,任何中斷處理函數都應該是可重入的。


線程安全的概念則是源自於多線程環境。起源不一樣,那麽他們之間也沒有什麽必然的關系。


面試題:

中斷是嵌入式系統中重要的組成部分。新的關鍵字_interrupt。下面的代碼就是用_interrupt關鍵字去定義了一個中斷服務子程序(ISR),然後評論下面的代碼;

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

代碼錯誤:

1、ISR不能返回一個值。

2、ISR不能傳遞參數。

3、在許多的處理器/編譯器中,浮點一般都是不可重入的。有些處理器/編譯器需要讓額外的寄存器入棧,有些處理器/編譯器你就是不允許在ISR中做浮點運算。此外,ISR應該是短而有效率的,在ISR中做浮點運算是不明智的。

4、printf()經常有重入和性能上的問題。


那麽在這裏就該有一個原則:

1、不要使用static變量和全局變量,堅持只用局部變量

2、如必須使用全局變量,利用互斥信號量來保護全局變量

3、獲取得知哪些系統調用是可重入的,在多任務處理程序中都使用安全的系統調用

4、不調用其他任何不可重入的函數

5、謹慎使用malloc/free



可重入函數與線程安全