Как защитить общий ресурс с помощью мьютексов?
У меня есть общий ресурс, к которому я хочу, чтобы 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
блок, который упрощает вещи.