How do you protect a common resource using mutexes?
I have a common resource, which I want 1 and only 1 instance of my application (or it's COM API) to have access to at any time. I have tried to protect this resource using mutexes, but when multiple threads of a host dotnet application try to access the COM object, the mutex doesn't seem to be released. This is the code I have used to protect my resource.
repeat
Mutex := CreateMutex(nil, True, PChar('Connections'));
until (Mutex <> 0) and (GetLastError <> ERROR_ALREADY_EXISTS);
try
//use resource here!
finally
CloseHandle(Mutex);
end;
If I run the threads simultaneously, the first thread get's through (obviously, being the first one to create the mutex), but subsequent threads are caught in the repeat loop. If I run each thread at 5 second intervals, then all is ok.
I suspect I'm not using mutexes correctly here, but I have found very little documentation about how to do this.
Any ideas?
You're using the mutex wrong. You should be waiting for it and releasing it, not recreating it constantly.
During initialization:
Mutex := CreateMutex(nil, False, 'Connections');
if Mutex = 0 then
RaiseLastOSError;
When you want to access the resource
if WaitForSingleObject(Mutex, INFINITE) <> WAIT_OBJECT_0 then
RaiseLastOSError;
try
// Use resource here
finally
ReleaseMutex(Mutex)
end;
During finalization
CloseHandle(Mutex);
Also, since mutexes are global, you should pick something a little more unique than "connections" for the name. We added a GUID to the end of ours.
Try with this simple demo code. Start several instances of the application, and you can see from the background colour how they share the mutex:
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;
Note that I chose to use the TMutex
class from the SyncObjs
unit, which simplifies things.
精彩评论