轉載出處 http://www.cnblogs.com/zhaoyl/archive/2012/10/03/2711018.htmlhtml
1. 三個概念,線程安全,可重入,信號安全程序員
先簡單提一下, 線程安全,主要是針對數據競爭來講的,就是說:若是數據不須要共享,那就讓每一個線程私有;若是須要共享,那就加鎖。 信號安全,其實也就是異步信號安全,是說線程在信號處理函數當中,無論以任何方式調用你的這個函數若是不死鎖不修改數據,那就是信號安全的。也就是說一個可重入函數在信號處理函數當中不影響調用他的人自己的狀態,其實就是一個task_struct有不少指針指向它,你經過多線程調一個可重入函數,函數有本身所在的task的代碼段和數據段,若是你在信號處理裏面調它,其實是換了一個指向同一個task_struct裏面內容的指針來操做,會有問題。這種情形經過加鎖是解決不了問題的,好比你正在調用printf過程當中,遇到一個信號,轉而去處理這個信號,而且在處理這個信號的信號處理函數當中正巧要調用printf,那麼屏幕上就是亂的,加鎖行不行呢?那就很好玩了。因此printf不是異步信號安全的。 可重入性:就是不管以什麼方式屢次調用都不會出現問題,不會出現對可能有修改的靜態數據的訪問,不會出現對全局變量(好比errno)的訪問。嚴格講可重入要區分線程安全(弱可重入)仍是信號安全(強可重入)兩點,可是通常說可重入就是指信號安全。因爲信號安全要求高於線程安全,因此說若是一個函數是可重入的,那必定是線程安全的(反之不必定)。 2. 下面詳細解釋三者 2.1 可重入性(reentrant)針對函數,它有兩個方面的內涵: 1)可並行/併發,同時進入:指可重入函數被某任務調用時,其它任務可同時進行調用而不產生錯誤的結果;或稱在相同的輸入狀況下可重入函數的執行所產生的效果,並不因其併發的調用而產生不一樣,也稱併發安全。 2)中斷後可從新進入:指可重入函數可被任意的中斷,當中斷執行完畢,返回斷點能夠繼續正確的運行下去;或稱在相同的輸入狀況下可重入函數的執行所產生的結果,並不由於在函數執行期間有中斷的調用而產生不一樣,也稱中斷安全。 可重入(reentrant)函數能夠由多於一個任務併發使用,而沒必要擔憂數據錯誤。相反, 不可重入(non-reentrant)函數不能由超過一個任務所共享,除非能確保函數的互斥 (或者使用信號量,或者在代碼的關鍵部分禁用中斷)。可重入函數能夠在任意時刻被中斷, 稍後再繼續運行,不會丟失數據。可重入函數要麼使用本地變量,要麼在使用全局變量時 保護本身的數據。 可重入函數通常要知足: 不爲連續的調用持有靜態數據。 不返回指向靜態數據的指針;全部數據都由函數的調用者提供。 使用本地數據,或者經過製做全局數據的本地拷貝來保護全局數據。 毫不調用任何不可重入函數。 出於如下任意某個緣由,其他函數是不可重入的: 它們調用了 malloc 或 free:malloc/free 是在 C 標準中規定的,而在 C 中是沒有進程/線程的概念。 衆所周知它們使用了靜態數據結構體。 它們是標準 I/O 程序庫的一部分:glibc的c庫算是線程安全了,卻不保證可重入或異步信號安全。 2.2 線程安全(MT-safe)不只僅針對函數,它主要是指數據或程序的安全這一結果,因此有不一樣的層次上講的線程安全:如線程安全的函數,線程安全的庫 。本文還會引入線程安全的類這一律念。一般意義上一個線程安全的函數是指有可重入函數第一個內涵的函數即併發安全的函數。但須要注意的是即便是一個從函數級別上並不安全的函數,若是使其不安全的因素在特定應用中並不存在時,這個函數對於該應用來說一樣也是線程安全的。例如對於全局變量的訪問,通常而言未命名同步方式訪問確定是非線程安全的,但若是全部可能同時發生的訪問均是隻讀訪問則從結果上講也是線程安全的。 不要混淆可重入與線程安全。在程序員看來,這是兩個獨立的概念:函數能夠是可重入的,是線程安全的,或者 兩者皆是,或者兩者皆非。不可重入的函數不能由多個線程使用。另外,或許不可能讓某個 不可重入的函數是線程安全的。關於標準IO庫是否是線程安全的要依據實際狀況而定,不一樣的庫有不一樣實現,通常爲了方便用戶使用,在支持多線程的系統上都配備了線程安全的庫,但卻不是以不安全的,由於,信號必定是異步的,不是線程的加鎖機制(本質是同步化)就能夠解決的。 2.3 信號安全,信號的本質軟中斷,中斷在本質上是異步的,所謂異步信號安全同線程安全同樣,也是站在結果上考慮的,指在信號的中斷處理過程當中的安全。一般意義上一個異步信號安全的函數是指能夠在異步信息處理函數中調用而不會出現異常的函數。一樣須要注意到即便一個從函數級別上並不是異步信息安全的函數,若是在信息處理函數中調用,也並不必定會產生不安全的結果。 3. 三個概念的異同 從函數級別考慮,僅從概念上就能夠發現可重入函數必定是線程安全函數,也是異步信號安全函數;多線程安全函數卻要弱得多,並不是必定要是可重入函數,它只要求併發無誤便可;雖然異步信號函數與可重入函數的描述方式有所不一樣,但二者從實現層面上講是徹底一致的。 參考文獻: 1 《使用可重入函數進行更安全的信號處理》 2 http://bbs.chinaunix.net/thread-942090-1-1.html