Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you protect a common resource using mutexes?

Tags:

mutex

delphi

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?

like image 860
Steve Avatar asked Mar 18 '10 15:03

Steve


2 Answers

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.

like image 110
Zoë Peterson Avatar answered Feb 12 '23 01:02

Zoë Peterson


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.

like image 38
mghie Avatar answered Feb 12 '23 03:02

mghie