可重入函式與執行緒安全

2021-07-05 00:02:14 字數 2171 閱讀 1465

執行緒安全:乙個函式被稱為執行緒安全的(thread-safe),當且僅當被多個併發程序反覆呼叫時,它會一直產生正確的結果。如果乙個函式不是執行緒安全的,我們就說它是執行緒不安全的(thread-unsafe)。我們定義四類(有相交的)執行緒不安全函式。

將這類執行緒不安全函式變為執行緒安全的,相對比較容易:利用像p和v操作這樣的同步操作來保護共享變數。這個方法的優點是在呼叫程式中不需要做任何修改,缺點是同步操作將減慢程式的執行時間。

乙個偽隨機數生成器是這類不安全函式的簡單例子。

unsigned int next = 1; 

int rand(void)

void srand(unsigned int seed)

rand函式是執行緒不安全的,因為當前呼叫的結果依賴於前次呼叫的中間結果。當我們呼叫srand為rand設定了乙個種子後,我們反覆從乙個單執行緒中呼叫rand,我們能夠預期乙個可重複的隨機數字序列。但是,如果有多個執行緒同時呼叫rand函式,這樣的假設就不成立了。

使得rand函式變為執行緒安全的唯一方式是重寫它,使得它不再使用任何靜態資料,取而代之地依靠呼叫者在引數中傳遞狀態資訊。這樣的缺點是,程式設計師現在要被迫改變呼叫程式的**。

某些函式(如gethostbyname)將計算結果放在靜態結構中,並返回乙個指向這個結構的指標。如果我們從併發執行緒中呼叫這些函式,那麼將可能發生災難,因為正在被乙個執行緒使用的結果會被另乙個執行緒悄悄地覆蓋了。

有兩種方法來處理這類執行緒不安全函式。一種是選擇重寫函式,使得呼叫者傳遞存放結果的結構位址。這就消除了所有共享資料,但是它要求程式設計師還要改寫呼叫者的**。

struct hostent* gethostbyname_ts(char* host)

如果函式f呼叫執行緒不安全函式g,那麼f就是執行緒不安全的嗎?不一定。如果g是類2類函式,即依賴於跨越多次呼叫的狀態,那麼f也是不安全的,而且除了重寫g以外,沒有什麼辦法。然而如果g是第1類或者第3類函式,那麼只要用互斥鎖保護呼叫位置和任何得到的共享資料,f可能仍然是執行緒安全的。比如上面的gethostbyname_ts。

可重入函式:可重入函式是執行緒安全函式的一種,其特點在於它們被多個執行緒呼叫時,不會引用任何共享資料。

可重入函式通常要比不可重入的執行緒安全函式效率高一些,因為它們不需要同步操作。更進一步說,將第2類執行緒不安全函式轉化為執行緒安全函式的唯一方法就是重寫它,使之可重入。

下面為rand函式的乙個可重入版本

int rand_r(unsigned int* nextp)

顯式可重入函式:如果所有函式的引數都是傳值傳遞的(沒有指標),並且所有的資料引用都是本地的自動棧變數(也就是說沒有引用靜態或全域性變數),那麼函式就是顯示可重入的,也就是說不管如何呼叫,我們都可斷言它是可重入的。

隱式可重入函式:可重入函式中的一些引數是引用傳遞(使用了指標),也就是說,在呼叫執行緒小心地傳遞指向非共享資料的指標時,它才是可重入的。例如rand_r就是隱式可重入的。

我們使用可重入(reentrant)來包括顯式可重入函式和隱式可重入函式。然而,可重入性有時是呼叫者和被呼叫者共有的屬性,並不只是被呼叫者單獨的屬性。

extern:

不可重入函式不可以在它還沒有返回就再次被呼叫;該函式在被呼叫還沒有結束之前,再次被呼叫,從而可能產生錯誤。 但是,可重入函式不存在這樣的問題。

不可重入函式在實現時通常使用了全域性的資源(eg. 全域性變數),在多執行緒的環境下,如果沒有很好的處理資料保護和互斥訪問,就可能會發生錯誤。

常見的不可重入函式有:

printf  ---引用全域性變數stdout;

malloc  ---全域性記憶體分配表,分配堆疊空間;

free ---全域性記憶體分配表,釋放堆疊空間;

以prinf為例,中斷在任何時候都可能發生,比如發生在prinft執行過程中,假若又發生了中斷巢狀,而此時stdout資源被占用,所以第二個中斷的printf等待第乙個中斷的stdout資源釋放,而第乙個中斷等待第二個中斷返回,造成了死鎖,這樣printf就發生了重入,這種情況是不允許的。

在unix裡面,通常會有加上_r的字尾同名可重入函式版本。如果實在沒有,不妨在可預見的發生錯誤的地方嘗試加上保護鎖同步機制等。

摘自:

執行緒安全與可重入函式

可重入函式 reentrant function 與執行緒安全函式 thread safe function 有時容易混淆,而且各種文件中的解釋也不是很清楚,這裡根據筆者的經驗來說明一下。執行緒安全函式 概念 執行緒安全的概念比較直觀。一般說來,乙個函式被稱為執行緒安全的,當且僅當被多個併發執行緒反...

可重入函式與執行緒安全

可重入函式與執行緒安全 執行緒安全 假如在乙個函式中它是這麼寫的,在乙個全域性鍊錶上存放資料,在單執行緒模式下,我們先new乙個新的節點然後讓head next指向這個節點,這種場景在多執行緒場景下會是這樣的過程,執行緒一new了乙個節點,然後cpu轉去執行執行緒二,執行緒二new乙個節點後head...

可重入函式與執行緒安全

若乙個程式或子程式可以 安全的被並行執行 parallel computing 則稱其為可重入 reentrant或re entrant 的。即當該子程式正在執行時,可以再次進入並執行它 並行執行時,個別的執行結果,都符合設計時的預期 可重入概念是在單執行緒作業系統的時代提出的。乙個子程式的重入,可...