1. 程式人生 > >不可重入函式與執行緒安全函式

不可重入函式與執行緒安全函式

      在多執行緒或有異常控制流的情況下,當某個函式執行到中途時,控制流(也就是當前指令序列)就有可能被打斷而去執行另一個函式. 如果在這種情況下不會出現問題,比如說資料或狀態不會被破壞,行為確定。那麼這個函式就被稱做"可重入"的.
 
補充:

      函式是可重入(reentrant)的,是指對於相同的(並且合法的)函式引數(包括無參函式的情況),多次呼叫此函式產生的行為是可預期的,即函式的行為一致,或者結果相同。不能保證這一點的函式稱為不可重入(non-reentrant)函式。

可重入和執行緒安全(Thread-Safe)是兩個不同的概念:可重入函式一定是執行緒安全的;執行緒安全的函式可能是重入的,也可能是不重入的;執行緒不安全的函式一定是不可重入的。


可重入函式:     Reentrant Function
執行緒安全函式:   Thread-Safe Function
可重入和執行緒安全不是一個概念。
可重入 => 執行緒安全


可重入函式要解決的問題是,不在函式內部使用靜態或全域性資料,不返回靜態或全域性資料,也不呼叫不可重入函式。


執行緒安全函式要解決的問題是,多個執行緒呼叫函式時訪問資源衝突。


函式如果使用靜態變數,通過加鎖後可以轉成執行緒安全函式,但仍然有可能不是可重入的,比如strtok。

strtok是既不可重入的,也不是執行緒安全的。

加鎖的strtok不是可重入的,但執行緒安全。

而strtok_r既是可重入的,也是執行緒安全的。

3. reentrant函式與thread safe函式的區別

       reentrant函式與是不是多執行緒無關,如果是reentrant函式,那麼要求即使是同一個程序(或執行緒)同時多次進入該函式時,該函式仍能夠正確的運作.該要求還蘊含著,如果是在多執行緒環境中,不同的兩個執行緒同時進入該函式時,該函式也能夠正確的運作.


thread safe函式是與多執行緒有關的,它只是要求不同的兩個執行緒同時對該函式的呼叫在邏輯上是正確的.


從上面的說明可以看出,reentrant的要求比thread safe的要求更加嚴格.reentrant的函式必是thread safe的,而thread safe的函式未必是reentrant的.

結論:
1. reentrant是對函式相當嚴格的要求,絕大部分函式都不是reentrant的(APUE上有一個reentrant函式
的列表).什麼時候我們需要reentrant函式呢?只有一個函式需要在同一個執行緒中需要進入兩次以上,我們才需要
reentrant函式.這些情況主要是非同步訊號處理,遞迴函式等等.(non-reentrant的遞迴函式也不一定會
出錯,出不出錯取決於你怎麼定義和使用該函式). 大部分時候,我們並不需要函式是reentrant的.


2. 在多執行緒環境當中,只要求多個執行緒可以同時呼叫一個函式時,該函式只要是thread safe的就可以了.
我們常見的大部分函式都是thread safe的,不確定的話請查閱相關文件.


3. reentrant和thread safe的本質的區別就在於,reentrant函式要求即使在同一個執行緒中任意地進入兩次以上,
也能正確執行.


大家常用的malloc函式是一個典型的non-reentrant但是是thread safe函式,這就說明,我們可以方便的
在多個執行緒中同時呼叫malloc,但是,如果將malloc函式放入訊號處理函式中去,這是一件很危險的事情.


4. reentrant函式肯定是thread safe函式,也就是說,non thread safe肯定是non-reentrant函式不能簡單的通過加鎖,來使得non-reentrant函式變成 reentrant函式.

"使用的全域性變數的函式也不一定是不可重入的。"這句是正確的,只要正確使用就可以了,但是不使用全域性變數是寫可重入函式的簡單方法.

轉載地址:http://blog.sina.com.cn/s/blog_a9303fd90101dilj.html