Конференция "Прочее" » Вопрос по дедлокам. [D7, IB6.x]
 
  • Дмитрий Белькевич (31.03.09 00:33) [0]
    Стоит ли на них строить нормальную логику работы приложения, или их нужно избегать всеми возможными методами?
  • Хибл Герзмаев (31.03.09 00:46) [1]
    что такое дедлок ?
  • DVM © (31.03.09 00:59) [2]
    как можно строить логику на дедлоках?
  • Коммуноцентрист1 (31.03.09 01:14) [3]

    > Стоит ли на них строить нормальную логику работы приложения

    нет :)

    > или их нужно избегать всеми возможными методами?

    нужно, но, и как в любом хорошем деле, главное, не расшибить лоб
  • Коммуноцентрист1 (31.03.09 01:23) [4]
    похоже, нулевая шишка уже есть, раз вопрос.
    опишите ситуацию, на сухой теории рассказывать можно, но неэффективно
  • Юрий Зотов © (31.03.09 03:28) [5]
    Дедлок (если, конечно, он действительно дедлок, а не просто ожидание) блокирует работу двух (как минимум) потоков, и из этого взаимного клинча их даже еще одним потоком не вышибить. Какую на этом можно построить логику приложения?
  • oxffff © (31.03.09 04:24) [6]

    > Дмитрий Белькевич   (31.03.09 00:33)  
    > Стоит ли на них строить нормальную логику работы приложения,
    >  или их нужно избегать всеми возможными методами?


    Deadlock - это определеноого рода ситуация ситуация.
    И если есть арбитр(еще один поток если хотите), который идентифицирует такую ситуацию и разрешает ее.
    Почему нет?
  • SPeller © (31.03.09 04:28) [7]
    thread1                                thread2
    WaitForSingleObject(thread2)
                                             SendMessage(thread1)


    Тут уж только потоки уничтожать насильно. Какую полезную логику тут можно построиь? :) Такого вообще не должно быть в нормальной программе.
  • KSergey © (31.03.09 07:30) [8]
    > Юрий Зотов ©   (31.03.09 03:28) [5]
    > из этого взаимного клинча их даже еще одним потоком не вышибить.
    >  Какую на этом можно построить логику приложения?

    Стоп-кран?
  • SPeller © (31.03.09 08:19) [9]
    а может, имеется ввиду некто "дедло"?
  • Виталий Панасенко (31.03.09 09:07) [10]
    Если использовать по крайней мере две транзакции(компонента): длинную читающую, короткую для изменения данных, то шансов получить "смертельные объятия" практически нет...
  • SPeller © (31.03.09 10:14) [11]
    MultiReaderSingleWriter
  • Palladin © (31.03.09 10:24) [12]
    Лучше строить логику на AV :)
  • Sergey Masloff (31.03.09 15:00) [13]
    Palladin ©   (31.03.09 10:24) [12]
    >Лучше строить логику на AV :)
    Золотые слова
  • oxffff © (31.03.09 15:52) [14]

    > Sergey Masloff   (31.03.09 15:00) [13]
    > Palladin ©   (31.03.09 10:24) [12]
    > >Лучше строить логику на AV :)
    > Золотые слова


    Прошу в студию доказательства однонаправленности понятий deadlock и AV.
  • Alkid © (01.04.09 10:24) [15]

    > Юрий Зотов ©   (31.03.09 03:28) [5]
    >
    > Дедлок (если, конечно, он действительно дедлок, а не просто
    > ожидание) блокирует работу двух (как минимум) потоков, и
    > из этого взаимного клинча их даже еще одним потоком не вышибить.
    >  Какую на этом можно построить логику приложения?

    Юр, ты разве не понимаешь? Дедлок - это высокоэффективная замена бесконечного пустого цикла! И если цикл потребляет процессор, то дедлок - нет. 100% экономия ресурсов! Причём, если цикл вводит в ступор только один поток, то дедлок - два и более! Это же повышение эффективности до 200%! И даже больше!


    > Palladin ©   (31.03.09 10:24) [12]
    > Лучше строить логику на AV :)

    +1
    Шутки шутками, а некоторые альтернативно одарённые программисты умудрялись широко использовать исключения для возврата значений из функций.
  • KSergey © (01.04.09 10:37) [16]
    > Alkid ©   (01.04.09 10:24) [15]
    > умудрялись широко использовать исключения для возврата значений из функций.

    или для перехода в конец функции, вместо goto.
  • clickmaker © (01.04.09 10:39) [17]
    > или для перехода в конец функции

    да здесь-то как раз нормально. Логика на исключениях выглядит иногда красивей, чем бесконечные вложенные ифы, особенно, если память много раз подо что-то выделяется
  • Alkid © (01.04.09 11:05) [18]

    > clickmaker ©   (01.04.09 10:39) [17]
    > да здесь-то как раз нормально. Логика на исключениях выглядит
    > иногда красивей, чем бесконечные вложенные ифы, особенно,
    >  если память много раз подо что-то выделяется

    Не нормально. Исключения не должны использоваться как штатный инструмент для передачи управления.
  • clickmaker © (01.04.09 11:07) [19]
    > Исключения не должны использоваться как штатный инструмент
    > для передачи управления

    да кто сказал?
    если у меня сложная форма с кучей валидаторов - лестница из ифов, уходящая за горизонт будет лучше?
  • oxffff © (01.04.09 12:09) [20]

    > Юрий Зотов ©   (31.03.09 03:28) [5]
    > Дедлок (если, конечно, он действительно дедлок, а не просто
    > ожидание) блокирует работу двух (как минимум) потоков, и
    > из этого взаимного клинча их даже еще одним потоком не вышибить.
    >  Какую на этом можно построить логику приложения?


    Не все так печально.

    1. WaitForMultipleObjects,
    2 .WaitForSingleObjectEx + Alertable + QueueUserAPC
    3. WaitForMultipleObjectsEx + Alertable+ QueueUserAPC
  • oxffff © (01.04.09 12:14) [21]
    Мне вообще не понятно, почему стали заменять понятие deadlock на механизм исключений. И даже стали выдавать баллы.
    Убежден в пригодности и полезности того и другого.
    Но это два совершенно разных понятия.
    Deadlock может присутствовать в логике.
    Исключения могут присутствовать для логики.
  • DVM © (01.04.09 12:17) [22]

    > Alkid ©   (01.04.09 11:05) [18]


    > Не нормально. Исключения не должны использоваться как штатный
    > инструмент для передачи управления.

    Нормально, одно из предназначения исключений как раз и есть отделение места возникновения ошибки от места ее обработки.
  • SPeller © (01.04.09 13:28) [23]
    А я думал что AV и исключения - это немного разные вещи
  • Дмитрий Белькевич (01.04.09 13:53) [24]
    Тема начала разрастаться... Извиняюсь за немного неверную поставновку проблемы. Имеются в виду не сами deadlock'и, а их отлов. Можно ли строить нормальную логику приложения на отлове no wait deadlocks и повторении действий.

    Deadlock'и всё таки ближе к av или к исключению?
  • Дмитрий Белькевич (01.04.09 14:04) [25]
    Не вижу ничего плохого в использование исключений в логике работы. Возраващать нормальные результаты из функции через исключение, наверно, не стоит. Но возвращать исключительные ситуации - вполне можно.
  • test © (01.04.09 14:10) [26]
    Дмитрий Белькевич   (01.04.09 13:53) [24]
    AV == access violation исключение
    av == исключение

    deadlock взаимное блокирование потоков друг другом, само по себе ошибку не вызвает.

    Какой то странный у тебя вопрос ИМХО...
  • KSergey © (01.04.09 14:11) [27]
    > Дмитрий Белькевич   (01.04.09 13:53) [24]
    > Имеются в виду не сами deadlock'и,  а их отлов. Можно ли строить нормальную логику приложения  на отлове no wait deadlocks и повторении действий.

    Растолкуйте своё понимание термина deadlock, плиз. В моём понимании - это именно непредвиденные (не запланированные) ситуации, в котороых 2 объекта взаимноблокируются так, что если их и можно разблокировать - то только сторонним участником взаимоотношений. О котором, возможно, не подумали про проектировании, и тогда только убить все приложение остается.

    Если же по дизайну приложения есть два цикла, котрые запланировано на определенных участках блокируют работу соседа - то это скоре просто получается межпоточная синхронизация, т.к. это по дизайну и не смертельно. deadlock'ов не возникает.
  • Дмитрий Белькевич (01.04.09 14:34) [28]
    Опишу проблему вообще, может другие идеи появятся.

    Есть два разных по функциональости потока (потомки tthread).

    Один периодически просыпается, открывает пишущую транзакцию (у неё nowait НЕ выставлен), и не закрывает её. Закрывается же она либо по тайм-ауту (внешним таймером), либо по достижении определенного количества циклов записи в базу. Сделано так ускорения работы потока. Можно было бы транзакцию сразу же закрывать, после записи в базу, однако это замедляет работу (которая критична по времени) где-то раза в 2.

    Когда работает один поток - то никаких особенных сложностей не возникает.

    Добавляем второй поток. Поток, если бы ему не мешал первый, спать не должен. Он открывает пишущую транзакцию (у неё nowait выставлен), делает 3-4 запроса, закрывает транзакцию, уходит дальше в цикл, пока не 'пробежит' все из нужных (2-3 миллиона) записей. Их список открыт (ibquery) в отельной (читающей) транзакции.

    Так вот. Пока потоки работают отдельно - всё нормально. Как только они начинают работать вместе - во втором, само собой начинают вылазить nowait deadlock'и.

    Отлавливаю их во втором потоке, откатываю транзакцию, усыпляю, делаю запрос снова.

    Теперь опишу проблему.

    Проблема в том, что при такой работе через некоторое время первый поток начинает медленно работать (в 10-50 раз). При этом сервер файрбёрда загружает одно из ядер на 100% (обычно - 50-80, если первый поток вообще работает). Приостанавливаю первый поток - загрузка падает почти до нуля.

    Второй поток можно приостановить или вообще разрушить - ничего не меняется. Первый пока не пробовал - попробую.

    Перезагружаю приложение - всё ок, всё работает. Пока опять оба потока одновременно к базе не лезут.

    Вот такая весёлая история...

    Да, FB - 2.1.1. На 2.0.3 - то же самое...

    Может быть - какие-нибудь специальные инструменты есть для работы с FB?

    Вроде же ничего особенного и не делаю...

    Два потока всего лезут к одной таблице...
  • Дмитрий Белькевич (01.04.09 14:36) [29]
    >av == исключение

    AV - это acess violation.

    Исключение - это exception.

    AV - это исключение, но исключение - это не AV. Не нужно путать.
  • test © (01.04.09 14:46) [30]
    Дмитрий Белькевич   (01.04.09 14:36) [29]

    >>AV - это исключение, но исключение - это не AV. Не нужно путать.

    Вот с этого момента поподробнее, что не путать?
    Тип исключения с исключением или что?

    Дмитрий Белькевич   (01.04.09 14:34) [28]

    procedure TMyThread.PushTheButton;
    begin
     Button1.Click;
    end;

    procedure TMyThread.Execute;
    begin
     ...
     Synchronize(PushTheButton);
     ...
    end;
  • Дмитрий Белькевич (01.04.09 14:53) [31]
    >Вот с этого момента поподробнее, что не путать? Тип исключения с исключением или что?

    Не тип исключения, а принцип исключения. AV - это всегда ошибка. А exception - это только исключительная ситуация. Которая может быть и ошибкой. А может и не быть.

    >Synchronize(PushTheButton);

    Зачем мне это? Я где-то говорил, что один из потоков - VCL? Я же специально написал - оба - потомки tthread.
  • Дмитрий Белькевич (01.04.09 14:56) [32]
    Исключение - если уж на то пошло - это вообще класс и его модификации. В отличие от AV.
  • test © (01.04.09 15:05) [33]
    Дмитрий Белькевич   (01.04.09 14:56) [32]
    То есть ошибки != исключительные ситуации?

    Дмитрий Белькевич   (01.04.09 14:53) [31]
    То есть их нужно как то разрулить без синхронизации между собой? Ну тогда мьютексы, сообщения и WaitForMultipleObjects не помогут.
  • SPeller © (02.04.09 03:01) [34]

    > То есть ошибки != исключительные ситуации?

    Ну чё пристал? AV это одна из составных частей понятия исключения. Если AV это стопудово исключение, то не каждое исключение - это AV.

    Лучше по существу человеку подскажи, чем демагогию устраивать :)
  • test © (02.04.09 06:31) [35]
    SPeller ©   (02.04.09 03:01) [34]
    Про синхонизировать опасный кусок я ему уже писал test ©   (01.04.09 14:46) [30].
  • test © (02.04.09 06:42) [36]
    SPeller ©   (02.04.09 03:01) [34]
    Ну а какие могут быть еще варианты кроме синхронизации тем или другим способом опасного метода?
  • Вариант (02.04.09 06:50) [37]

    > Дмитрий Белькевич   (01.04.09 14:34) [28]

    Вариантов может быть несколько. Если есть приоритетный поток (или выполняющий очень короткие и быстрые операции с базой), то его задача дать знать другому о необходимости "освободить базу", то есть завершить активную транзакцию и ждать команды на продолжение потока, что достигается синхронизацией например через событие для потока, которым надо управлять или другими способами (мне просто видится проще синхронизация на событии (Event)  в данном случае, транзакции у обоих потоков "ждущие").  
    Или более простой на мой взгляд вариант - в базу пишет один поток, просто он имеет очередь запросов приоритетную и обычную. Или даже одну очередь - это уже по условиям задачи...
  • test © (02.04.09 06:55) [38]
    Вариант   (02.04.09 06:50) [37]
    Если в момент получения события второй поток надолго сидит в какой нибудь процедуре, то событие он получит как бы потом.
  • Вариант (02.04.09 07:03) [39]

    > test ©   (02.04.09 06:55) [38]

    Да, например он пишет в базу - ну так пусть закончит корректно запись и потом получит событие. Это почти при любом способе синхронизации так, когда поток уже скажем захватил разделяемы ресурс.
    Кстати я вижу это несколько иначе, чем обычная сигнализация событий. Событие установлено изначально - то есть оно разрешает потоку писать, а вот перед записью стоит WaitForXXX с тайм-аутом=0, по тай-ауту активная транзакция завершается и тайм-аут меняется на INFINITE/ А если вышел из функции по WAIT_OBJECT_- то значит можно продолжать писать в базу. Ну а второй поток просто висит в ожидании на транзакции, как первый завершил свою транзакцию, второй начал свою... Но как я писал выше, вариантов исполнения может быть куча. Я бы может писал бы и одним потоком с очередями запросов... Надо смотреть конкретные условия задачи
  • test © (02.04.09 07:13) [40]
    Вариант   (02.04.09 07:03) [39]
    В любом случае надо сигнализировать потоку что процедура занята, переменной или сообщением или блоком синхронизации. Зачем выдумывать лисапеды если есть стандартные средства Дельфи Synchronize например, у него еще парочка таких же, но под дедлоком обычно подразумевают блокировку в разных местах, например первый открыл файл и не отдает, в это время второй открыл другой файл и ждет когда можно будет записать в файл первого, а первый ждет когда можно будет записать в файл второго, и все ждут пока программу не рубанут.
  • Вариант (02.04.09 07:34) [41]

    > test ©   (02.04.09 07:13) [40]

    Между TThread Synchronize не работает... ну по крайней мере для версии дльфи 6:-) Объект событие ->Event (который создается CreateEvent) -является вполне стандартным средством (лисапедом) ОС Windows, кстати в дельфи у него есть обертка -класс  TEvent.
    Дедлок в данном контексте вопроса у автора - это дедлок возникающий у транзакции, у него одна транзакция с параметрами nowait. То есть он пытается стартовать транзакцию, но так как записи блокированы другой транзакцией, то он после страта транзакции сразу  и получает дедлок - транзакции - тоже способ синхронизации, только организуются на уровне СУБД.  Если бы он запускал ждущую транзакцию, то получал бы дедлок, если транзакция не смогла стартовать после указанного периода времени (вроде для FB по умолчанию 10 сек, но могу и соврать, сто лет уже не работал с ним).  
    Но я не претендую на единственно верный вариант исполнения. Я просто даю свое видение решения проблемы.
  • Вариант (02.04.09 08:03) [42]

    > Вариант   (02.04.09 07:34) [41]


    > если транзакция не смогла стартовать после указанного периода
    > времени

    Уточнение,
    читать как -
    если транзакция не смогла  выполнить операцию (как правило, изменения данных) за указанный период  времени
  • Дмитрий Белькевич (02.04.09 21:58) [43]
    >Зачем выдумывать лисапеды если есть стандартные средства Дельфи Synchronize например

    Synchronize, насколько мне известно, работает только с VCL.

    Удалось синхронизировать два потока вызов функции приостанавливающей другой поток.

    Дедлоки перестали возникать. Однако - проблема осталась. Пока не могу найти причину.

    Прямо в работе останавливаю, убиваю, создаю, стартую оба треда - проблема остаётся - скорость первой уменьшается, бывает, раз в 100.

    Побреду на ибэйз... Может какой интсрумент присоветуют.
  • test © (03.04.09 09:29) [44]
    Дмитрий Белькевич   (02.04.09 21:58) [43]
    Приоритеты нитям расставь.
  • MsGuns © (03.04.09 11:46) [45]
    А вот мне интересно из каких кустов произрастают подобные проблемы :)
  • Дмитрий Белькевич (03.04.09 20:51) [46]
    >Приоритеты нитям расставь.

    Тут проблема в том, что тормозить-то начинает не моё приложение, а FB сервер. Поэтому нет смысла.

    А вообще у того потока, который тормозит - и так уже tpHighest стоит.

    В одном треде - несколько селектов, делит и инсерт в цикле.

    В другом треде - 2 апдейта и селект в цикле.

    Работа идёт с 3-мя таблицами, кроме запросов и таблиц в действе участвуют еще несколько триггеров и хп (достаточно простых). Вроде бы ничего выдающегося. Никаких ошибок, само собой.

    >А вот мне интересно из каких кустов произрастают подобные проблемы :)

    Да уже скоро неделю мозгом об стол бьюсь :)

    Добавил логи (благо, всё обращение к базе, кроме хп, через один класс идёт). Ну ничего выдающегося - запросы как запросы. По отдельности - работают без проблем. Через какое-то рандомное время, без видимых причин, начинают запросы где-то раза 2.5-3 медленнее выполнятся, причем только на первом треде...

    Пересоздание одного, другого или обоих тредов ничего не меняет.
 
Конференция "Прочее" » Вопрос по дедлокам. [D7, IB6.x]
Есть новые Нет новых   [134478   +44][b:0][p:0.001]