1. 程式人生 > >執行緒安全與可重入函式之間的區別

執行緒安全與可重入函式之間的區別

今天,學到了兩個概念。執行緒安全、與可重入函式 這個都是關於多執行緒的,下面我們來看看這兩個概念到底有什麼不同之處。

先來看看這兩個概念

1、什麼是可重入函式

函式被不同的控制流程呼叫,有時會在之前的函式正在訪問函式變數的時候,執行緒被切出去執行別的流程再次在別的執行緒放訪問當前的函式,這個過程叫做是重入。  詳細說的話,

假設當前的程式是多執行緒的程式 ,當程式執行到某一個函式的時候,可能因為硬體中斷或者異常而使得在使用者正在執行的程式碼暫時終端轉而進入你核心,這個時候如有一個訊號需要被處理,而處理的這個訊號的時候又會重新呼叫剛才中斷的函式,如果函式內部有一個全域性變數需要被操作,那麼,當訊號處理完成之後重新返回使用者態恢復中斷函式的上下文再次繼續執行的時候,對同一個全域性變數的操作結果可能就會發生改變而並不如我們預期的那樣,這樣的函式被稱為不可重入函式。例如在進行連結串列的的插入時,插入函式訪問一個全域性連結串列,有可能因為重入而造成錯亂。

相對應的,當一個執行流因為異常或者被核心切換而中斷正在執行的函式而轉為另外一個執行流時,當後者的執行流對同一個函式的操作並不影響前一個執行流恢復後執行函式產生的結果,我們就稱這個函式為可重入函式

可重入函式只訪問自己的區域性變數或引數

其實總結就是:一個可重入函式可以被多個執行流重複進入,內部使用的資料都應該來自於自身的棧空間,包括返回值也不應該是全域性或者靜態的,可以允許有該函式的多個副本在執行,而正是因為其中的操作資料都來自於自身的棧空間,而每次呼叫函式會開闢不同的棧空間,因此二者互不影響。

2、什麼是執行緒安全

 當多個執行緒類併發操作某類的某個方法,(在該方法內部)來修改這個類的某個成員變數的值,不會出錯,則我們就說,該的這個方法是執行緒安全的。

  某類的某方法是否執行緒安全的關鍵是:

  (1) 該方法是否修改該類的成員變數;

  (2) 是否給該方法加鎖(是否用synchronized關鍵字修飾)

所以,有這麼四類函式稱為執行緒不安全的

1、不保護共享變數的函式;
2、函式狀態隨著呼叫改變的函式;
3、返回指向靜態變數指標的函式;
4、呼叫執行緒不安全函式的函式;

如果你的程式碼所在的程序中有多個執行緒在同時執行,而這些執行緒可能會同時執行這段程式碼如果每次執行結果和執行的結果是一樣的,而且其他的變數的值也和預期的是一樣的,就是執行緒安全的。或者說一個類或者程式所提供的介面對於執行緒來說是原子操作或者多個執行緒之間的切換不會導致該介面的執行結果存在二義性,也就是說我們不用考慮同步的問題。

執行緒安全問題都是由全域性變數及靜態變數引起的。若每個執行緒中對全域性變數、靜態變數只有讀操作,而無寫操作,一般來說,這個全域性變數是執行緒安全的;若有多個執行緒同時執行寫操作,一般都需要考慮執行緒同步,否則的話就可能影響執行緒安全。
一般來說,一個函式被稱為執行緒安全的,當且僅當被多個併發執行緒反覆呼叫時,它會一直產生正確的結果

3、可重入函式的分類

(1)顯式可重入函式
如果所有函式的引數都是傳值傳遞的(沒有指標),並且所有的資料引用都是本地的自動棧變數(也就是說沒有引用靜態或全域性變數),那麼函式就是顯示可重入的,也就是說不管如何呼叫,我們都可斷言它是可重入的。
(2)隱式可重入函式
     可重入函式中的一些引數是引用傳遞(使用了指標),也就是說,在呼叫執行緒小心地傳遞指向非共享資料的指標時,它才是可重入的。
       可重入函式可以有多餘一個任務併發使用,而不必擔心資料錯誤,相反,不可重入函式不能由超過一個任務所共享,除非能確保函式的互斥(或者使用訊號量,或者在 程式碼的關鍵部分禁用中斷)。可重入函式可以在任意時刻被中斷,稍後再繼續執行,不會丟失資料,可重入函式要麼使用本地變數,要麼在使用全域性變數時保護自己 的資料。

一個可重入函式需要滿足的是:

1、不使用全域性變數或靜態變數;
2、不使用用malloc或者new開闢出的空間;
3、不呼叫不可重入函式;
4、不返回靜態或全域性資料,所有資料都有函式的呼叫者提供;
5、使用本地資料,或者通過製作全域性資料的本地拷貝來保護全域性資料;

不可重入函式符合以下條件之一:
1、呼叫了malloc/free函式,因為malloc函式是用全域性連結串列來管理堆的。
2、呼叫了標準I/O庫函式,標準I/O庫的很多實現都以不可重入的方式使用全域性資料結構
3、可重入體內使用了靜態的資料結構。

4、執行緒安全與可重入函式的區別

(1)、可重入函式是執行緒安全函式的一種,其特點在於它們被多個執行緒呼叫時,不會引用任何共享資料。
(2)、執行緒安全是在多個執行緒情況下引發的,而可重入函式可以在只有一個執行緒的情況下來說。(3)、執行緒安全不一定是可重入的,而可重入函式則一定是執行緒安全的。(4)、如果一個函式中有全域性變數,那麼這個函式既不是執行緒安全也不是可重入的。(5).如果將對臨界資源的訪問加上鎖,則這個函式是執行緒安全的,但如果這個重入函式若鎖還未釋放則會產生死鎖,因此是不可重入的。(6)、執行緒安全函式能夠使不同的執行緒訪問同一塊地址空間,而可重入函式要求不同的執行流對資料的操作互不影響使結果是相同的。