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;
А выносить наружу Lock/Unlock я бы стал с особой осторожностью.
Вы привели классический пример потенциально возможного deadlock-а. Ваш вариант по сути ничем не отличается от:
function TMyObj.DoSomething: Integer;
begin
FCS.Enter;
try
Result := SendMessage(SomeHandle, WM_MYMESSAGE, FA mod 3, FB mod 4);
finally
FCS.Leave;
end;
end;
Дедлок гарантированно будет, если вы в обработчике сообщения WM_MYMESSAGE попытаетесь изменить значения свойства A или B.
function TMyObj.DoSomething: Integer;
begin
FCS.Enter;
try
Result := SendMessage(SomeHandle, WM_MYMESSAGE, FA mod 3, FB mod 4);
finally
FCS.Leave;
end;
end;
то будет. SendMessage ждет обработки сообщения, а значит выхода из критической секции не будет до тех пор, пока мы не обработаем сообщение. В свою очередь в обработчике если мы обратимся к свойству A или B — код остановится на входе в критическую секцию и будет ждать освобождения её, которого не будет.
Разумеется это хороший и разумный способ. И я упомянул о подобном в статье:
Нижним уровнем абстракции будем считать работу с объектами синхронизации (критические секции, мьютексы, семафоры). Верхним — такие парадигмы программирования, как Futures and promises, STM (software transactional memory), обмен асинхронными сообщениями и т.п. Верхний уровень абстракции зачастую всегда основан на нижнем.
Всегда стараюсь уходить от примитивов синхронизации
Тут имелась ввиду не синхронизация в деструкторе, а синхронизация деструктора и других методов объекта. В деструкторе вообще нет смысл вызывать синхронизацию, она должна быть снаружи, и суть данной синхронизации заключается как раз в том, что вы сказали. Пока хоть кто-то выполняет метод объекта — удалять объект нельзя. В случае работы с интерфейсами — да можно произвести захват ссылки, это и будет решением синхронизации. Но есть ведь еще не интерфейсы, а объекты, которые удаляют по obj.Free. В этом случае нужно другое решение.
Допустим поток Б зашел и выполняет метод объекта obj.DoSomething. Поток А хочет уничтожить объект, и обнуляет ссылку на объект у себя, и у потока Б. Ссылок на объект не осталось, поэтому уничтожаем объект. Но код в obj.DoSomething при этом еще не успел отработать.
Спасибо за ссылку. Как бы объяснить, суть в том, что когда архитектура проекта разрастается, проект развивается, какой-то код меняется и т.п. становится сложно уследить за дедлоками. Поэтому я стараюсь писать потокобезопасные классы так, что как бы этот класс не использовали — дедлока гарантированно не будет, а когда у класса есть коллбек евенты — это особо актуально. С практикой — я пришел к выводу, что предупредить дедлоки можно только так, как я описал в статье. Граф это конечно хорошо, и он правильно описывает ситуацию с дедлоками, но непонятно, как в условиях изменяющегося кода предупреждать их?
Хм… поторопился с «не встречал». Встречал конечно же, но как построить такой граф по коду — я не знаю. Блокировку становится видно только когда она уже случается. В связи с этим я пришел к выше описываемому подходу, который на практике помогает мне избегать блокировок.
Печально конечно, если так. Я лично в равной степени уважаю все языки программирования, и я бы конечно же описал статью на С++, т.к. большинству понятнее читать на нем, но к сожалению у меня мало практики работы с этим языком (знание тонкостей стандартных классов и т.п.), и дабы не допустить ляп — я описал на том языке, с которым каждый день работаю.
Спасибо за очевидное правило. К сожалению слишком мало находил материалов по борьбе с дедлоками, и такого определения не встречал. Получается что мой случай — частный случай графа без циклов. С другой стороны если оперировать вашим вариантом, то непонятно как диагностировать такие проблемы, потому что пока блокировку не схватишь — не поймешь этого.
Я понимаю, что статья может не нравится. Поэтому прошу, прежде чем кидать минус (тем более в карму) хотя бы в общих чертах объяснить, что именно плохо, чтобы я мог проанализировать свои ошибки, и не совершать их в дальнейшем.
Спасибо.
А как по мне — так госдума поступает вполне логично. Они увидели в интернете угрозу. Эти всякие шествия на Болотных площадях и т.п. Нужен механизм контроля, и под видом «блага» для нас они этот механизм получают. Все эти прикрытия сайтов — только для отвода глаз, настоящая цель — контролировать этих революционеров, подбивающих народ на сборы/митинги. Вспомните заодно про запрет анонимности в интернете. По-моему отличный способ борьбы с неугодными.
Программа же используется для моделирования, а не для того чтобы произвести вау эффект на обычного пользователя. Так что от просто визуализатора толку мало. Это надо заниматься разработкой самих фонтанов. А для этого надо разбираться во всей этой гидравлике, связать все это с dmx контроллером и написать редактор сценариев для dmx контроллера. Монетизировать тут пока нечего, да и потом, сам визуализатор лично для меня итак «монетизирован». Я же не за спасибо писал его ;)
В первом варианте они падали на землю, но в реальных фонтанах падающую воду видно хуже, и так пожелал именно заказчик. Поэтому мы решили, что после прохождения верхней точки у частиц надо увеличивать прозрачность, чтобы постепенно они стали невидимыми.
А выносить наружу Lock/Unlock я бы стал с особой осторожностью.
Дедлок гарантированно будет, если вы в обработчике сообщения WM_MYMESSAGE попытаетесь изменить значения свойства A или B.
то будет. SendMessage ждет обработки сообщения, а значит выхода из критической секции не будет до тех пор, пока мы не обработаем сообщение. В свою очередь в обработчике если мы обратимся к свойству A или B — код остановится на входе в критическую секцию и будет ждать освобождения её, которого не будет.
Всегда стараюсь уходить от примитивов синхронизации
Спасибо.