在多任務系統下,中斷可能在任務執行的任何時間發生,同時也可能在任務執行過程中發生系統調度而將執行轉向另一個線程,如果一個函數的執行期間被中斷后,到重新恢復到斷點進行執行的過程中,函數所依賴的環境沒有發生改變,那么這個函數就是可重入的,否則就不可重入。
滿足下面條件的多數是不可重入的:
(1)使用了靜態數據結構;
(2)調用了malloc或free;
(3)調用了標準I/O函數;
(4)進行了浮點運算.
malloc/free是不可重入的,它們使用了全局變量來指向空閑區;標準I/O庫的很多實現都使用了全局數據結構; 許多的處理器/編譯器中,浮點一般都是不可重入的 (浮點運算大多使用協處理器或者軟件模擬來實現)。
linux/unix中的async-signal-safe
知乎上有類似的討論, linux/unix中可重入的概念一般是要求async-signal-safe,而linux下很多線程安全的函數卻都是不可重入的,比如malloc。因為 linux/unix中,signal是以軟中斷方式分發的,signal handler可能在任何時候打斷一個進程的任意線程而執行(如果該線程沒有屏蔽該signal的話)。比如在執行某函數A的過程中,signal handler打斷線程B中A的執行,然后在線程B的上下文中開始執行處理,在處理中又調用了A,由于A不是異步可重入的,所以會導致嚴重的問題。
一般情況下可重入會比線程安全更嚴格一些,因為線程安全是針對多線程而言的:A function that may be safely invoked concurrently by multiple threads。因為可以通過互斥鎖等手段使得在多線程環境下對函數的調用得到正確的結果。但如果在函數的調用中嵌套調用了函數自身,可能會因互斥鎖而引起死鎖,導致函數不可重入。
可重入要求在函數執行過程中被信號中斷處理時再次進入該函數之后,調用均可以得到正確的結果。