可重入函數與線程安全

介紹:

      一組併發線程運行在同一進程上下文中,每一個線程都有自己獨立的線程上下文,包括線程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



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章