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

執行緒安全與可重入

執行緒安全一個函式被稱為執行緒安全的當且僅當被多個併發執行緒反覆呼叫時,它會一直產生正確的結果。
上面已經提到,執行緒不安全的根源在於:共享資料。
共享資料可以是:
1 函式把返回結果放到一個公共的位置
2 由呼叫者傳入的執行緒間共享的指標變數或者引用變數
3 函式內部本來就會使用的共享靜態變數
任何執行緒不安全問題的根源都是“共享資料”所以,不使用任何共享資料的函式(即:可重入函式)肯定是執行緒安全的。但這並不等於說,執行緒安全函式就是可重入函式。為什麼呢?因為即使有執行緒有共享資料,執行緒被併發呼叫的時候產生的結果可以是正確的。那麼這種正確性是如何保證的呢?對,就是通過同步操作。
執行緒不安全怎麼能夠改寫成執行緒安全
無非有兩種策略:
1 仍舊使用共享資料,但是在使用共享資料的時候做同步操作。對於函式過程中使用的共享資料,可以進行簡單的PV操作,對於返回結果可以在PV操作中把共享資料拷貝到非共享的位置,以便及時釋放共享變數。
2 杜絕使用共享變數。也就是說把函式改成了可重入的函式。但是,徹底杜絕共享變數有的時候不容易做到。對於上面的提到的第一種和第三種情況很容易做到,但是對於第二種情況,我們沒有辦法。所以,對於一個不接受引用和指標的函式,我們可以把它做到絕對的可重入,但是,對於一個接受指標或者引用的函式來說,對不起,我們不能確保他肯定是可重入的。
關於效能:
  通常來說,多執行緒是為了在同一時間內能夠處理更多的同樣型別的事情,但是執行緒不安全卻阻礙了我們達到我們的目的。所以,我們有的時候不得不想方設法的把執行緒不安全的函式改寫成執行緒安全的。
  改寫的結果無非兩種,一種是原函式的“同步版本”,一種是原函式的“可重入版本”。可重入版本相比前者的從效能
上來說有著天然的優勢,這種優勢就是在於它不涉及PV操作,不存在軟體上的瓶頸,可以最大化的利用硬體資源。然而“同步版本”則有可能不能充分利用硬體的資源,因為程式在等待資源的釋放。關於重寫的策略
  拿到一個執行緒不安全函式是一件鬱悶的事情。你必須要使用它,怎麼辦呢?這個時候就要從上面提到的三個可能的共享資料來入手了:
1  如果呼叫函式的返回結果是共享的,這個時候就要使用上面提到的lock-and-copy方法,在PV操作中,把結果轉移到非共享的區域。
2 嘗試在呼叫函式的時候不使用引用或者指標,如果函式在多執行緒工作的時候結果正確了,則為題解決了,否則,問題可能出現在函式內部,轉3
3 找到這個函式的共享變數,對其做PV操作。
可重入當被多個執行緒呼叫的時候,不會引用任何共享資料。
可重入函式:如果一個函式只訪問自己的區域性變數或引數,則稱為可重入(Reentrant) 函式。(可重入函式一定是執行緒安全的)