How do you protect a common resource using mutexes?

13,739

Solution 1

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.

Solution 2

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.

Share:
13,739
Steve
Author by

Steve

Born a Developer, will die a developer!

Updated on June 11, 2022

Comments

  • Steve
    Steve almost 2 years

    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?