天天看點

C:可重入函數 & 線程安全函數

線程安全:簡單來說線程安全就是多個線程并發同一段代碼時,不會出現不同的結果,我們就可以說該線程是安全的。

線程安全産生的原因:大多是因為對全局變量和靜态變量的操作。

常見的線程不安全的函數:

(1)不保護共享變量的函數;

(2)函數狀态随着被調用,狀态發生變化的函數;

(3)傳回指向靜态變量指針的函數;

(4)調用線程不安全函數的函數;

常見的線程安全的情況:

(1)每個線程對全局變量或者靜态變量隻有讀取的權限,而沒有寫入的權限,一般來說這些線程是安全的;

(2)類或者接口對于線程來說都是原子操作;

(3)多個線程之間的切換不會導緻該接口的執行結果存在二義性;

可重入函數

重入:同一個函數被不同的執行流調用,目前一個流程還沒有執行完,就有其他的程序已經再次調用(執行流之間的互相嵌套執行);

可重入   :多個執行流反複執行一個代碼,其結果不會發生改變,通常通路的都是各自的私有棧資源;

不可重入:多個執行流反複執行一段代碼時,其結果會發生改變;

可重入函數:當一個執行流因為異常或者被核心切換而中斷正在執行的函數而轉為另外一個執行流時,當後者的執行流對同一個函數的操作并不影響前一個執行流恢複後執行函數産生的結果;

不可重入函數:當程式運作到某一個函數的時候,可能因為硬體中斷或者異常而使得在使用者正在執行的代碼暫時終端轉而進入核心,這個時候如有一個信号需要被處理,而處理的這個信号的時候又會重新調用剛才中斷的函數,如果函數内部有一個全局變量需要被操作,那麼,當信号處理完成之後重新傳回使用者态恢複中斷函數的上下文再次繼續執行的時候,對同一個全局變量的操作結果可能就會發生改變而并不如我們預期的那樣,這樣的函數被稱為不可重入函數。

可重入函數滿足條件:

(1)不使用全局變量或靜态變量;

(2)不使用用malloc或者new開辟出的空間;

(3)不調用不可重入函數;

(4)不傳回靜态或全局資料,所有資料都有函數的調用者提供;

(5)使用本地資料,或者通過制作全局資料的本地拷貝來保護全局資料;

不可重入函數條件(符合以下之一):

(1)調用了malloc/free函數,因為malloc函數是用全局連結清單來管理堆的。

(2)調用了标準I/O庫函數,标準I/O庫的很多實作都以不可重入的方式使用全局資料結構。

(3)可重入體内使用了靜态的資料結構。

可重入函數分類:

(1)顯式可重入函數

如果所有函數的參數都是傳值傳遞的(沒有指針),并且所有的資料引用都是本地的自動棧變量(也就是說沒有引用靜态或全局變量),那麼函數就是顯示可重入的,也就是說不管如何調用,我們都可斷言它是可重入的。

(2)隐式可重入函數

可重入函數中的一些參數是引用傳遞(使用了指針),也就是說,在調用線程小心地傳遞指向非共享資料的指針時,它才是可重入的。

可重入函數可以有多于一個任務并發使用,而不必擔心資料錯誤,相反,不可重入函數不能由超過一個任務所共享,除非能確定函數的互斥(或者使用信号量,或者在 代碼的關鍵部分禁用中斷)。可重入函數可以在任意時刻被中斷,稍後再繼續運作,不會丢失資料,可重入函數要麼使用本地變量,要麼在使用全局變量時保護自己的資料。

------------------------可重入函數與線程安全的差別與聯系-------------------------

C:可重入函數 & 線程安全函數

聯系:

函數可以是可重入的   ---=--->  線程安全的。

差別:

(1)可重入函數是線程安全函數的一種,其特點在于它們被多個線程調用時,不會引用任何共享資料。

(2)線程安全是在多個線程情況下引發的,而可重入函數可以在隻有一個線程的情況下來說。

(3)線程安全不一定是可重入的,而可重入函數則一定是線程安全的。

(4)如果一個函數中有全局變量,那麼這個函數既不是線程安全也不是可重入的。

(5)如果将對臨界資源的通路加上鎖,則這個函數是線程安全的,但如果這個重入函數若鎖還未釋放則會産生死鎖,是以是不可重入的。

(6)線程安全函數能夠使不同的線程通路同一塊位址空間,而可重入函數要求不同的執行流對資料的操作互不影響使結果是相同的。

REF: https://blog.csdn.net/double_happiness/article/details/72877112

              https://blog.csdn.net/u010027547/article/details/48158803

繼續閱讀