如果你的**所在的程序中有多個執行緒在同時執行,而這些執行緒可能會同時執行這段**。如果每次執行結果和單執行緒執行的結果是一樣的,而且其他的變數的值也和預期的是一樣的,就是執行緒安全的,或者多個執行緒之間的切換不會導致該介面的執行結果存在二義性。
執行緒安全問題都是由全域性變數及靜態變數引起的。
若每個執行緒中對全域性變數、靜態變數只有讀操作,而無寫操作,一般來說,這個全域性變數是執行緒安全的;若有多個執行緒同時執行寫操作,一般都需要考慮執行緒同步,否則的話就可能影響執行緒安全。
舉例:
乙個 arraylist 類,在新增乙個元素的時候,它可能會有兩步來完成:
1、 在 items[size] 的位置存放此元素;
2、 增大 size 的值。
在單執行緒執行的情況下,如果 size = 0,新增乙個元素後,此元素在位置 0,而且 size=1; 而如果是在多執行緒情況下,比如有兩個執行緒,執行緒 a 先將元素存放在位置 0。但是此時 cpu 排程執行緒a暫停(此時size並未改變),執行緒 b 得到執行的機會,執行緒b也向此 arraylist 新增元素,因為此時 size 仍然等於 0 所以執行緒b也將元素存放在位置0。然後執行緒a和執行緒b都繼續執行,都增加 size 的值。 對於arraylist,我們期望有兩個元素 ,實際上只有乙個,存放在位置 0,而 size 等於 1,造成了元素丟失,這就是「執行緒不安全」了。
所謂可重入函式是指乙個可以被多個任務呼叫的過程,任務在呼叫時不必擔心資料是否會出錯,若出錯了,則是不可重入函式;
main函式調⽤用insert函式向⼀個鍊錶head中插⼊節點node1,插入操作分為兩步,剛做完第一步的時候,因為硬體中斷使程序切換到核心,再次回⽤使用者態之前檢查到有訊號待處理,於是切換 到sighandler函式,sighandler也調⽤insert函式向同⼀個鍊錶head中插入節點node2,插⼊操作的兩步都做完之後從sighandler返回核心態,再次回到⽤戶態就從main函式調⽤用的insert函式中繼續 往下執行,先前做第⼀步之後被打斷,現在繼續做完第⼆步。結果是,main函式和sighandler先後 向鍊錶中插⼊兩個節點,⽽而最後只有⼀個節點真正插⼊入煉表中了。
像上例這樣,insert函式被不同的控制流程呼叫,有可能在第⼀次呼叫還沒返回時就再次進入該函式,這稱為重入,insert函式訪問⼀個全域性鍊錶,有可能因為重⼊⽽而造成錯亂,像這樣的函式稱為 不可重入函式,反之,如果乙個函式只訪問⾃自⼰的區域性變數或引數,則稱為可重⼊(reentrant) 函式。
滿足下列條件的函式多數是不可重入的:
1) 函式體內使用了靜態的資料結構;
2) 函式體內呼叫了malloc()或者free()函式;
3) 函式體內呼叫了標準i/o函式。
二者之間的關係:
1、乙個函式對於多個執行緒是可重入的,則這個函式是執行緒安全的。
2、乙個函式是執行緒安全的,但並不一定是可重入的。
執行緒安全與可重入函式
可重入函式 reentrant function 與執行緒安全函式 thread safe function 有時容易混淆,而且各種文件中的解釋也不是很清楚,這裡根據筆者的經驗來說明一下。執行緒安全函式 概念 執行緒安全的概念比較直觀。一般說來,乙個函式被稱為執行緒安全的,當且僅當被多個併發執行緒反...
可重入函式與執行緒安全
執行緒安全 乙個函式被稱為執行緒安全的 thread safe 當且僅當被多個併發程序反覆呼叫時,它會一直產生正確的結果。如果乙個函式不是執行緒安全的,我們就說它是執行緒不安全的 thread unsafe 我們定義四類 有相交的 執行緒不安全函式。將這類執行緒不安全函式變為執行緒安全的,相對比較容...
可重入函式與執行緒安全
可重入函式與執行緒安全 執行緒安全 假如在乙個函式中它是這麼寫的,在乙個全域性鍊錶上存放資料,在單執行緒模式下,我們先new乙個新的節點然後讓head next指向這個節點,這種場景在多執行緒場景下會是這樣的過程,執行緒一new了乙個節點,然後cpu轉去執行執行緒二,執行緒二new乙個節點後head...