2012-03-21 30 views
1

我正在寫一些代碼來執行顯式鏈接到一個DLL。此代碼作爲隱式鏈接到.lib文件的替代方法提供給我的用戶。目前,我計劃的代碼如下所示:我是否需要爲此代碼添加同步?

void DisableModule(int Module) 
{ 
    typedef void (*DisableModuleProc)(int); 
    static DisableModuleProc proc = NULL; 
    if (proc == NULL) 
     proc = (DisableModuleProc)GetProcAddress(hModule, "DisableModule"); 
    proc(Module); 
} 

有很多這種形式的功能,我已經切除了錯​​誤檢查這個問題的目的。

我的問題與線程安全有關。這個函數可能會被多個線程同時調用。顯然在靜態變量_DisableModule上有一場比賽。我的看法是,因爲_DisableModule將根據機器字邊界(32或64位邊界取決於目標)對齊,所以不會發生撕裂,所以比賽是良性的。 GetProcAddress可能會被調用超過必要次數,但我認爲這不會影響程序的正確性。

我的分析是否正確?

+0

被調用函數(_DisableModule)本身是線程安全嗎?此外,以下劃線和大寫字母開頭的標識符被保留。 – zvrba 2012-03-21 12:49:15

+0

@zvrba是的,導入的函數是線程安全的。非常感謝有關保留標識符的建議。我一點都不流利。 – 2012-03-21 12:51:37

+0

取決於處理器的類型,但是在x86或x64上,這將工作得很好。不太確定ARM,它有一個弱的內存模型。使用線程時始終明智地調用'比安全更安全'。 – 2012-03-21 12:53:00

回答

2

此代碼是在x86和AMD64萬無一失。 最壞情況GetProcAddress被稱爲幾次。

在其他體系結構中,部分寫入操作可能會中斷。爲了規避這一點,你可以使用原子(InterlockedComparExchange ...),但這在這裏是多餘的。

+0

那麼你是說在某些體系結構中,機器字大小對齊的寫入在讀取方面不是原子的? – 2012-03-21 13:40:41

+1

艾姆,有指針不是字大小的體系結構...(例如,16位拱,32位(遠)指針),或者允許寫入未對齊的地址,但可能不是原子緩存線邊界... 。但是你不能在他們上面運行窗口......。 – Christopher 2012-03-21 13:49:58

0

一個簡單的鎖應該這樣做。
只有在proc==NULL的情況下,您才應該取鎖,所以過了一段時間後永遠不會被取走。所以爭用不是問題。
您可以在保持鎖定的情況下撥打GetProcAddress,或者不用。

選項1:

if (proc == NULL) { 
    lock(); 
    proc = (DisableModuleProc)GetProcAddress(hModule, "DisableModule"); 
    unlock(); 
} 

選項2:

if (proc == NULL) { 
    DisableModuleProc tmp = (DisableModuleProc)GetProcAddress(hModule, "DisableModule"); 
    lock(); 
    if (proc == NULL) { 
     proc = tmp; 
    } else { 
     // Any free needed? 
    } 
    unlock(); 
} 
+0

謝謝你,但我試圖避免需要鎖。 – 2012-03-21 17:24:32

+0

如果'GetProcAddress'是線程安全的,並且總是返回相同的值,那麼你確實很好。但鎖的成本幾乎沒有我提出的方式。 – ugoren 2012-03-21 19:25:18

+0

它是線程安全的。但如果不是那麼你的選擇2會失敗。 – 2012-03-21 19:31:20