Как защитить общий ресурс с помощью мьютексов?

У меня есть общий ресурс, к которому я хочу, чтобы 1 и только 1 экземпляр моего приложения (или это COM API) имели доступ в любое время. Я попытался защитить этот ресурс с помощью мьютексов, но когда несколько потоков приложения host 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 секунд, то все в порядке.

Я подозреваю, что я не использую мьютексы правильно здесь, но я нашел очень мало документации о том, как это сделать.

какие идеи?

2 ответов


вы неправильно используете мьютекс. Вы должны ждать его и выпускать, а не воссоздавать постоянно.

во время инициализации:

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 к концу нашего.


попробуйте с этим простым демо-кодом. Запустите несколько экземпляров приложения, и вы можете увидеть из цвета фона, как они разделяют мьютекс:

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 блок, который упрощает вещи.