Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
pthread_mutex_lock
в глобальной хэш-таблице отмечается, какие мьютексы уже были взяты на момент взятия данного мьютекса. То есть динамически строится граф зависимостей, и если в нем обнаруживается цикл — выдается ошибка, мол, нарушение порядка взятия мьютексов.pthread_mutex_lock
, то есть при каждой попытке взять мьютекс вызывается наш код. Есть thread-local storage, там эта обертка запоминает каждый взятый мьютекс. И есть глобальная хэш-таблица. Там при каждом взятии мьютекса запоминается, что когда брали мьютекс X, мьютексы A,B,C,D уже были взяты. Получается граф зависимостей, типа «A,B,C,D перед X». Ну и обычным рекурсивным поиском ищем циклы — если, например, есть «Y перед C» и «X перед Y», то получится цикл.Нижним уровнем абстракции будем считать работу с объектами синхронизации (критические секции, мьютексы, семафоры). Верхним — такие парадигмы программирования, как Futures and promises, STM (software transactional memory), обмен асинхронными сообщениями и т.п. Верхний уровень абстракции зачастую всегда основан на нижнем.
function TMyObj.DoSomething: Integer;
begin
FCS.Enter;
try
Result := SendMessage(SomeHandle, WM_MYMESSAGE, FA mod 3, FB mod 4);
finally
FCS.Leave;
end;
end;
function TMyObj.DoSomething: Integer;
begin
FCS.Enter;
try
Result := SendMessage(SomeHandle, WM_MYMESSAGE, FA mod 3, FB mod 4);
finally
FCS.Leave;
end;
end;
function TMyObj.DoSomething: Integer;
var k, n: Integer;
begin
FCS.Enter;
try
k := FA mod 3;
n := FB mod 4;
finally
FCS.Leave;
end;
Result := SendMessage(SomeHandle, WM_MYMESSAGE, k, n);
end;
если поток А ожидает ресурс, и при этом он не заблокировал ни один ресурс, то его в свою очередь никто не ожидает, а значит взаимной блокировки быть не может.В таком виде можно писать «Hello world'ы», но к сожалению редко что-то серьезнее. Ваш этот частный случай подразумевает, что все потоки делают разные действия, что на практике как раз очень тяжело добиться — распараллеливая потоки, где-то всегда получим пересечения (читать/писать файл/сокет, обращения к очередям, банкам данных, да мало ли что). И проблема здесь гораздно глубже — не раз ловил deadlock, казалось бы на совсем асинхронных кусках, совсем вроде без синхронизации. И deadlock на два треда ловится на раз-два-три — самый противный deadlock это что-то вида:
A ждет mutex(B)
B ждет database.rowlock(C)
C ждет file.lock(D)
D ждет ....
и где-то тут
Z ждет mutex(A)
И совсем класно, когда все это не только многопоточно, но и многопроцессно…A ждет mutex(B)
B ждет database.rowlock(C)
C ждет file.lock(D)
D ждет ....
и где-то тут
Z ждет mutex(A)
Согласно моему принципуТак я об этом и говорю — на практике (если не «Hello world») практически не могу себе представить — вплоть до потери смысла многопоточности (потоки распараллеливаются, т.е. все делается в результате однопоточно).
потоки распараллеливаются, т.е. все делается в результате однопоточно
Согласно моему принципу — если мы отправляем в ожидание поток B, то мы должны освободить его мьютексы.А тут надо еще добавить «закоммитить все транзакции, закрыть все блокирующие statements, file locks и т.д.».
Чтобы выбрать задачу из списка — нужно заблокировать список на момент выбора.Ну это за уши притянуто…
Моя «парадигма» работы с потоками