2010-03-18 68 views
6

我有一個公共資源,我想要1,並且只有1個我的應用程序實例(或它的COM API)可以隨時訪問。我試圖使用互斥體來保護這個資源,但是當一個主機dotnet應用程序的多個線程嘗試訪問COM對象時,互斥體似乎不會被釋放。這是我用來保護我的資源的代碼。如何使用互斥鎖保護公共資源?

repeat 
    Mutex := CreateMutex(nil, True, PChar('Connections')); 
until (Mutex <> 0) and (GetLastError <> ERROR_ALREADY_EXISTS); 
    try 
    //use resource here! 
    finally 
    CloseHandle(Mutex); 
    end; 

如果我同時運行的線程,第一個線程通過獲得的(當然,是第一個創建互斥),但隨後的線程都陷入重複循環。如果我以5秒的間隔運行每個線程,則一切正常。

我懷疑我在這裏沒有正確使用互斥鎖,但是我發現關於如何做到這一點的文檔很少。

任何想法?

回答

14

您正在使用互斥錯誤。你應該等待它並釋放它,而不是不斷地重新創建它。

在初始化過程中:

Mutex := CreateMutex(nil, False, 'Connections'); 
if Mutex = 0 then 
    RaiseLastOSError; 

當你要訪問的資源

if WaitForSingleObject(Mutex, INFINITE) <> WAIT_OBJECT_0 then 
    RaiseLastOSError; 
try 
    // Use resource here 
finally 
    ReleaseMutex(Mutex) 
end; 

在定稿

CloseHandle(Mutex); 

而且,由於互斥是全球性的,你應該挑些比較這個名字比「連接」更獨特。我們在我們的結尾添加了一個GUID。

+0

我應該補充說,這隻適用於將CreateMutex的第二個參數設置爲True的情況。否則,我會遇到和以前一樣的問題,每個掛起的線程都在等待對方。 – Steve 2010-03-18 16:17:13

+0

奇怪。 WaitForSingleObject調用應該爲你獲取互斥量。 MSDN示例也使用False:http://msdn.microsoft.com/en-us/library/ms686927%28VS.85%29.aspx – 2010-03-18 17:33:18

+1

克雷格是正確的。我的建議是*從不*通過'真'的第二個參數。原因是當函數返回時,你不知道你是否真的擁有互斥鎖。而且,在創建時,您可能不需要擁有互斥量。當程序啓動時,創建一次*互斥*。然後在程序運行時獲取並釋放它。當程序終止時,關閉手柄。每次需要擁有它時,不要創建並銷燬互斥鎖​​。 – 2010-03-18 20:31:30

10

試試這個簡單的演示代碼。啓動應用程序的多個實例,並且可以從背景顏色看看他們如何共享互斥:

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    fMutex := SyncObjs.TMutex.Create(nil, False, 'GlobalUniqueName'); 
end; 

procedure TForm1.FormDestroy(Sender: TObject); 
begin 
    fMutex.Free; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    Color := clRed; 
    Update; 
    fMutex.Acquire; 
    try 
    Color := clGreen; 
    Update; 
    Sleep(5 * 1000); 
    finally 
    fMutex.Release; 
    end; 
    Color := clBtnFace; 
end; 

請注意,我選擇使用TMutex類從SyncObjs單元,這簡化了操作。

+1

這也是一個很好的答案,但克雷格首先發布,他的代表比你低。我希望我能接受這兩個都是很好的答案。 – Steve 2010-03-18 15:43:40