2008-12-09 71 views

回答

21

重入代碼在單點中沒有狀態。您可以在代碼執行過程中調用代碼。如果代碼使用全局狀態,則可以設想一次調用覆蓋全局狀態,從而中斷另一次調用中的計算。

線程安全代碼是沒有競爭條件或其他併發問題的代碼。競爭條件是兩個線程執行某些操作會影響計算的順序。典型的併發問題是對共享數據結構的更改可能部分完成並保持不一致狀態。爲了避免這種情況,您必須使用併發控制機制(例如互斥信號量),以確保在操作完成之前沒有其他人可以訪問數據結構。

例如,如果一段代碼通過互斥體進行外部保護,但它仍具有全局數據結構,並且在整個調用過程中狀態必須一致,則該代碼段可以不可重入,但是線程安全。在這種情況下,同一個線程可以啓動一個回調過程,同時仍受外部粗粒互斥體的保護。如果回調發生在非重入過程中,則調用可能會使數據結構處於可能打破主叫方觀點計算的狀態。

如果代碼片段可以對共享(可共享)數據結構進行非原子更改(可在更新過程中被中斷而離開數據結構),則它可以是可重入的但非線程安全的處於inc inctent狀態。在這種情況下,訪問數據結構的另一個線程可能會受到半變更數據結構的影響,並且可能會崩潰或執行破壞數據的操作。

+3

你的第二個例子對我來說聽起來並不重要。如果改變可以被中斷而留下不一致的狀態,並且在該點發生信號,並且該信號的處理程序調用該功能,則通常情況會變得繁榮。這是一個重入問題,而不是線程安全問題。 – 2008-12-09 12:22:29

8

那篇文章說:

「的功能可以是可重入,線程安全的,這兩者或兩者都不是。」

它還說:

「不可重入函數是線程安全的」。

我可以看到這可能會導致混亂。它們表示不需要重入的標準函數也不需要是線程安全的,這對POSIX庫iirc來說是正確的(POSIX聲明它也適用於ANSI/ISO庫,ISO有沒有線程的概念,因此也沒有線程安全的概念)。換句話說,「如果一個函數說它是不可重入的,那麼它就是說它也是線程不安全的」。這不是一個合乎邏輯的必要性,這只是一個慣例。

這是一些線程安全的僞代碼(好吧,由於鎖定反轉,有很多機會回調創建死鎖,但讓我們假設文檔包含足夠的信息供用戶避免),但不可重入。它應該遞增全局計數器,並執行回調:

take_global_lock(); 
int i = get_global_counter(); 
do_callback(i); 
set_global_counter(i+1); 
release_global_lock(); 

如果回調再次調用該程序,造成另一個回調,那麼回調的兩個水平將得到相同的參數(這可能是好的,取決於API),但計數器只會增加一次(這幾乎肯定不是你想要的API,所以它將不得不被禁止)。

這是假設鎖是遞歸的,當然。如果鎖是非遞歸的,那麼代碼當然是不可重入的,因爲第二次取鎖是行不通的。

下面是一些僞代碼,這是「弱重入」,但不是線程安全的:

int i = get_global_counter(); 
do_callback(i); 
set_global_counter(get_global_counter()+1); 

現在它的罰款來調用回調函數,但它不是安全的同時調用該函數來自不同的線程。從信號處理程序中調用它也是不安全的,因爲如果信號發生在正確的時間,信號處理程序的再次入侵也可能破壞計數。因此,通過正確的定義,代碼是不可重入的。這裏有一些代碼可以說是完全可重入的(除了我認爲標準區分了可重入信號和'不可被信號中斷',而且我不確定它會在哪裏下降),但仍然不是線程化的,安全:

int i = get_global_counter(); 
do_callback(i); 
disable_signals(); // and any other kind of interrupts on your system 
set_global_counter(get_global_counter()+1); 
restore_signal_state(); 

在單線程應用程序中,這很好,假設操作系統支持禁用所有需要禁用的內容。它可以防止在臨界點發生重新入侵。根據信號被禁用的方式,從信號處理程序調用可能是安全的,儘管在這個特定的例子中仍然存在傳遞給回調的參數對於不同的調用相同的問題。不過,它仍然可能會出現多線程錯誤。因爲(非正式地)由於線程被調度程序中斷而可能出錯的任何事情,並且從另一個線程再次調用的函數也可以是非線程安全的,因此非線程安全通常意味着不可重入線程如果線程被信號中斷,並且信號處理程序再次調用該函數,則會出錯。但是,然後用於防止信號(禁用它們)的「修復」與用於防止併發的「修復」(通常爲鎖定)不同。這是最好的經驗法則。

請注意,我在此暗示了全局變量,但如果函數將參數指向計數器和鎖,則會應用完全相同的考慮事項。只是在使用相同參數調用各種情況時,線程不安全或不可重入,而不是完全被調用。