Как вы защищаете общий ресурс с помощью мьютексов? - PullRequest
6 голосов
/ 18 марта 2010

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

15 голосов
/ 18 марта 2010

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

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

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

11 голосов
/ 18 марта 2010

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

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, что упрощает работу.

...