2010-03-18 14 views
6

Ich habe eine gemeinsame Ressource, die ich will 1 und nur 1 Instanz meiner Anwendung (oder es ist COM API) zu jeder Zeit Zugriff haben. Ich habe versucht, diese Ressource mit Mutexe zu schützen, aber wenn mehrere Threads einer Host-Dotnet-Anwendung versuchen, auf das COM-Objekt zuzugreifen, scheint der Mutex nicht freigegeben zu sein. Dies ist der Code, mit dem ich meine Ressource geschützt habe.Wie schützt man eine gemeinsame Ressource mit Mutexen?

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

Wenn ich die Threads gleichzeitig ausgeführt werden, der erste Thread gets durch (offensichtlich, wobei der erste den Mutex erstellen), aber nachfolgende Threads werden in der Wiederholungsschleife gefangen. Wenn ich jeden Thread in 5-Sekunden-Intervallen abspiele, dann ist alles in Ordnung.

Ich vermute, dass ich nicht Mutexe hier richtig verwende, aber ich habe sehr wenig Dokumentation darüber gefunden, wie dies zu tun ist.

Irgendwelche Ideen?

Antwort

14

Sie verwenden den Mutex falsch. Du solltest darauf warten und es freigeben, es nicht ständig neu erstellen.

Während der Initialisierung:

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

Wenn Sie die Ressource

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

Während der Finalisierung

CloseHandle(Mutex); 

auch zugreifen möchten, da mutexes global sind, sollten Sie etwas holen mehr einzigartig als "Verbindungen" für den Namen. Wir haben eine GUID am Ende von uns hinzugefügt.

+0

Ich sollte hinzufügen, dass dies nur funktioniert, wenn ich den zweiten Parameter von CreateMutex auf True festlegen. Ansonsten bekomme ich das gleiche Problem wie zuvor mit aufgehängten Threads, die jeweils aufeinander warten. – Steve

+0

Ungerade. Der WaitForSingleObject-Aufruf sollte den Mutex für Sie erwerben. Das MSDN-Beispiel verwendet ebenfalls False: http://msdn.microsoft.com/en-us/library/ms686927%28VS.85%29.aspx –

+1

Craig hat Recht. Meine Empfehlung ist es, für den zweiten Parameter 'niemals' den Wert 'Wahr' zu übergeben. Der Grund dafür ist, dass Sie, wenn die Funktion zurückkehrt, keine Ahnung haben, ob Sie tatsächlich den Mutex besitzen. Zum Zeitpunkt der Erstellung müssen Sie den Mutex wahrscheinlich sowieso nicht besitzen. Erstelle den Mutex * einmalig * wenn dein Programm startet. Dann erwerbe und veröffentliche es, während dein Programm läuft. Schließen Sie das Handle, wenn Ihr Programm beendet wird. Erstelle und zerstöre den Mutex nicht jedes Mal, wenn du ihn besitzen musst. –

10

Versuchen Sie mit diesem einfachen Demo-Code. Starten Sie mehrere Instanzen der Anwendung, und Sie können von der Hintergrundfarbe sehen, wie sie die Mutex teilen:

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; 

Bitte beachte, dass ich die TMutex Klasse von der SyncObjs Einheit zu verwenden, entschied sich, die Dinge vereinfacht.

+1

Das ist auch eine gute Antwort, aber Craig hat zuerst gepostet und er hat weniger Reputation als du. Ich wünschte, ich könnte beides akzeptieren, denn beide sind großartige Antworten. – Steve

Verwandte Themen