PDA

Просмотр полной версии : Крит секции.


Yegor
22.08.2011, 01:29
Господа кто как ищет в программе взаимо-блокировки которые могут возникнуть при использовании крит секций. Есть для этого какие то специальные методы?

Например у меня в программе есть несколько потоков которые одновременно могут взаимодействуют с несколькими объектами. В каждый объекте есть свои крит секции.
Я заметил что блокировка может как правило возникнуть в следующей ситуации:

Первый поток обращается к первому объекту и использует его крит секцию.
Одновременно второй поток обращается ко второму обхекту с его крит.секц.
Первый поток пытается обратится ко второму обхекту не выходя из крит секции первого. И соответвенно ждет пока из этой к.с. выйдет второй поток.
Второй поток пытается обратится к первому объекту не выходя из к.с. второго. И соответственно все зависает на веки вечные.

Для упрощения работы с крит секциями в каждом обхекте я создал по 2 функции EnterCS и LeaveCS.
Если бы иметь возможность внутри этих функций мониторить состояние крит секций других моих объектов я мог бы хотя бы определить где и что привело к блокировке.

mira
22.08.2011, 10:19
В нт системах есть tryentercriticalsection в ряде случаев позволяющаяя избежать дедлоков. В идеале постарайся сделать синхронизацию по иерархии чтоб секции порядком выше не вызывались кодом низшего порядка. Если незнаеш где дедлок можеш юзать мутекс - таже секция но можно задать время ожидания и если оно вышло вывести месагу отладочную.

Добавлено через 3 минуты
Зы трайэнтер это посути и есть попытка войти в секцию но проверив ее состояние и если занята не пытатса ее ждать. Как она обернута в делфи хз я vcl не юзаю.

etoken
22.08.2011, 11:04
SyncObjs.TCriticalSection.TryEnter не покатит?

з.ы. я нуп на делфях не писал

Yegor
22.08.2011, 14:24
Да есть функция tryentercriticalsection ноне совсем пойму логику ее использования. Выполняя эту функцию я могу сразу знать захвачена эта крит секция другим потоком или нет, если да то какие мои действия, мне ведь все равно нужно в нее войти когда она освободится?
На ум приходит только зацикливать с каким то интервалом tryentercriticalsection пока она не захватит успешно объект крит. секции или пока не истечет какое то время.

etoken
22.08.2011, 14:37
логика в том что бы дождаться освобождения крит секции, да наверное надо лупится пока занято, но это точно исключит дедлоки...

А так Тряй вам поможет с:
"Если бы иметь возможность внутри этих функций мониторить состояние крит секций других моих объектов я мог бы хотя бы определить где и что привело к блокировке." ))

Yegor
22.08.2011, 14:51
etoken, в смысле в коде моего входа в крит секцию пытаться войти в крит секции других объектов для проверки занятости, например:

bool MyInterCritSect()
{
if (TryEnterCriticalSection(cs2))//проверяем не занята ли крит секция второго объекта
{//если нет
LeaveCriticalSection(cs2);
EnterCriticalSection()cs1);
return true;
}
else
{//если да
ShowMessage("Возможно блокирование ищите ошибку в логике программы:)");
return(false);
}
}


"Лупится" - это загрузит систему, если вызывать Sleep() то затормозит программу


Вот что по этому поводу пишет некий Oraizer

"Я считаю TryEnterCriticalSection() вообще бесполезной. Идеология критических секций такова, что они призваны защищать инварианты структур данных в пределах одного приложения в предположении, что нарушения инвариантов кратковременны, а значит коллизии случаются редко. Критические секции в отличие от мьютексов очень легки, приложение может их использовать сотнями, тысячами и больше, не особо нагружая систему. Отсюда и некоторые их ограничения, в частности отсутствие таймаутов, невозможность комбинировать их с другими объектами синхронизации и неопределённость поведения системы при несоблюдении правил обращения с ними. В таких исходных условиях TryEnterCriticalSection() может быть полезна в единственном случае - попробовать захватить и отказаться выполнять запрошенное действие в случае неудачи. Ни разу не припомню, чтобы мне понадобился такой сценарий. Всё остальное от лукавого, критические секции в других условиях эксплуатации просто вряд ли вообще подходят.
Средством защиты от deadlocks является отладка. Их просто не должно быть. Обходные пути в лице нарушенных инвариантов - это ещё большее зло."

Источник (http://forum.sources.ru/index.php?showtopic=327727&st=15)

Добавлено через 5 минут
А так Тряй вам поможет с:
"Если бы иметь возможность внутри этих функций мониторить состояние крит секций других моих объектов я мог бы хотя бы определить где и что привело к блокировке." ))

Как мне поможет Try? Изменить глобальное время ожидания входа в крит секцию в системе InitializeCriticalSectionAndSpinCount() и при исключении долгого ожидания искать ошибки в программе?

etoken
22.08.2011, 16:28
Как мне поможет Try? Изменить глобальное время ожидания входа в крит секцию в системе InitializeCriticalSectionAndSpinCount() и при исключении долгого ожидания искать ошибки в программе?
по крайне мере позволит понять в какой момент беда в логике синхронизации. Я имею ввиду использование так как вы описали в примере выше, тупо чекать состояние второй крит. секции, а там уже пытаться "понятть и простить".

mira
22.08.2011, 18:19
etoken, в смысле в коде моего входа в крит секцию пытаться войти в крит секции других объектов для проверки занятости, например:

bool MyInterCritSect()
{
if (TryEnterCriticalSection(cs2))//проверяем не занята ли крит секция второго объекта
{//если нет
LeaveCriticalSection(cs2);
EnterCriticalSection()cs1);
return true;
}
else
{//если да
ShowMessage("Возможно блокирование ищите ошибку в логике программы:)");
return(false);
}
}


"Лупится" - это загрузит систему, если вызывать Sleep() то затормозит программу


Вот что по этому поводу пишет некий Oraizer

"Я считаю TryEnterCriticalSection() вообще бесполезной. Идеология критических секций такова, что они призваны защищать инварианты структур данных в пределах одного приложения в предположении, что нарушения инвариантов кратковременны, а значит коллизии случаются редко. Критические секции в отличие от мьютексов очень легки, приложение может их использовать сотнями, тысячами и больше, не особо нагружая систему. Отсюда и некоторые их ограничения, в частности отсутствие таймаутов, невозможность комбинировать их с другими объектами синхронизации и неопределённость поведения системы при несоблюдении правил обращения с ними. В таких исходных условиях TryEnterCriticalSection() может быть полезна в единственном случае - попробовать захватить и отказаться выполнять запрошенное действие в случае неудачи. Ни разу не припомню, чтобы мне понадобился такой сценарий. Всё остальное от лукавого, критические секции в других условиях эксплуатации просто вряд ли вообще подходят.
Средством защиты от deadlocks является отладка. Их просто не должно быть. Обходные пути в лице нарушенных инвариантов - это ещё большее зло."

Источник (http://forum.sources.ru/index.php?showtopic=327727&st=15)

Добавлено через 5 минут


Как мне поможет Try? Изменить глобальное время ожидания входа в крит секцию в системе InitializeCriticalSectionAndSpinCount() и при исключении долгого ожидания искать ошибки в программе?

все прально написал чувак, трайэнтер скорее поможет диагностировать наличие дедлока нежели будет иметь практическое применение.
как я сказал выше постарайся сделать иерархию какуюто и попробуй избежать лишних "секций в секциях".
я трайэнтер не юзал, юзал мутекс с ожиданием скажем в 10 сек - если за это время не удавалось его захватить выводилась мессага о взаимоблокировке в таком-то месте

alexteam
22.08.2011, 20:12
Если бы иметь возможность внутри этих функций мониторить состояние крит секций других моих объектов я мог бы хотя бы определить где и что привело к блокировке.
eurekalog. поможет если дезлочиться основной поток приложения.

xkor
23.08.2011, 02:00
хм, чего не писал ещё ни разу не возникало необходимости использовать критические секции внутри критической секции, в связи с чем ни о каких взаимных блокировках и думать не приходиться)
имхо любую задачу можно реализовать без вложенных критических секций...

Yegor
23.08.2011, 13:03
Да это в трейд боте там такого я понакручивал. В основном проблеммы бывают с основым потоком при заполнение визуальных компонентов. Случаются ситуация когда необходимо одновременно захватить крит секции двух разных объектов. Я конечно стараюсь обходить такие ситуации использую промежуточные переменные но это неудобно и бывает допускаю ошибки которые потом тяжело найти.

mira
24.08.2011, 12:06
Зачем в трейдере такие расколбасы?
У меня синхронизируетса 3 нити:
1)поток клиента: рисование интерфейса, ввод клавы/мышки, прочие хуки.
2)Контрольный поток : обслуживает радар, разбирает и диспетчирует очередь пакетов проги, отслеживает состояние ядра программы, при необходимости формирует события для 3го потока.
3)рабочий поток: в нем крутитса скрипт и обрабатываютса события передаваемые скрипту

в итоге даже самым стремным скриптом сложно вывести программу из строя. На край этот поток завершитса с ошибкой или может быть "убит" и запущен заново.

дедлоков нет тока благодаря миниальной вложености блокировок и соблюдения "иерархии"

Yegor
24.08.2011, 13:08
У меня в 1 приложении запускается сразу n+ окон которые могут взаимодейтсвовать друг с другом.

Для каждого окна следующие потоки:

1. Поток приема и разбора пакетов. Он сам практически ничего не делает. Принял пакет, обработал, обновил соответствующие данные и ушел ждать следующего пакета.

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

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

4. Поток выполнения коротких действий. Например взять пати, сесть на трейд, отправить письмо, пробежать посмотреть цены в выделенной зоне. Может быть запущен из любого потока включая главный, на каждое окно может ыть одновременно запущено несколько таких потоков. Обычно этот поток отрабатывает свою задачу и уничтожается.


Ну и главный поток приложения в котором при необходимости перерисовывается интерфейс, выводится карта, рассчитывается положение движущихся объектов на карте в данный момент времени.

mira
24.08.2011, 14:50
3 и 4 разумнее в одно обьединить. Смысла создавать 5 вообще не вижу никакова смысла.
В 6 проблем быть недолжно - зашол в секцию -> считал данные -> обновил данные -> запер секцию. Обычно этот поток никто не ждет и дедлок исключен. Ему просто кидаетса евент или месага что пора обновитса.

etoken
24.08.2011, 15:20
Понублю: А чем крит секция принципиально отличается от мутексов ?

mira
24.08.2011, 15:38
Смысл один. У мутанта больше возможностей.
1 м может быть глобальной и доступной в других процессах. Секция тока в своем.
2 м можно захватить одним потоком неск.раз (ессно чтоб освободить нада стокаже раз вызвать release) секция же скорее всего "сломаетса" при двух ентерах или ливах.

понятно что цена за это скорость, мутекс требует обращения к ядру ос а это пассивный irq level

GoodDrone
24.08.2011, 15:57
2 м можно захватить одним потоком неск.раз (ессно чтоб освободить нада стокаже раз вызвать release) секция же скорее всего "сломаетса" при двух ентерах или ливах.

да вы, батенька, фантазёр:

After a thread has ownership of a critical section, it can make additional calls to EnterCriticalSection or TryEnterCriticalSection without blocking its execution. This prevents a thread from deadlocking itself while waiting for a critical section that it already owns. The thread enters the critical section each time EnterCriticalSection and TryEnterCriticalSection succeed. A thread must call LeaveCriticalSection once for each time that it entered the critical section.

Yegor
24.08.2011, 16:53
3 и 4 разумнее в одно обьединить.
Тогда тяжело будет реализовать всякие плюшки в бою. Такие как смена локаций когда заканчиватются нужные мобы, подсчет квестовых предметов, реакция на появление игроков в радиусе видимости.

Нет конечно это все можно сделать в потоке боя с помощью кучи настраевамых параметров, но тут теряется шибкость. Текст скрипта я могу проверять на перезапуская программу и на ходу настраивать пошагово.

mira
24.08.2011, 17:48
да вы, батенька, фантазёр:
ну.. я написал "скорее всего". непроверял ибо не допускал таково :)
смысл в том что у нее нет счетчика блокировок.

GoodDrone
24.08.2011, 18:01
смысл в том что у нее нет счетчика блокировок.
Есть таймаут, правда глобальный.

mira
24.08.2011, 18:17
Есть таймаут, правда глобальный.

впервые слышу что у секции есть таймаут.
у мутекса есть задаваемый вручную от 0 до INFINITE

xkor
24.08.2011, 19:02
mira, у TryEnterCriticalSection можно задать таймаут, после которого если так и не удалось войти в секцию, то TryEnterCriticalSection завершается возвращая соответствующий код результата. Собсно даже не можно а нужно, и так же от 0 до INFINITE

GoodDrone
24.08.2011, 19:21
mira, у TryEnterCriticalSection можно задать таймаут...
Где?

впервые слышу что у секции есть таймаут.

Я нашел только глобальный:

The timeout interval is specified by the following registry value: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Contro l\Session Manager\CriticalSectionTimeout.

xkor
24.08.2011, 19:30
GoodDrone, хм, да, чтот я гоню, нет у них таймаута при TryEnterCriticalSection, с чем то его перепутал видать

mira
24.08.2011, 19:47
трайэнтер мы причислили к извращениям вроде :)
поэтому InitializeCriticalSectionAndSpinCount не считаетса

Yegor
24.08.2011, 23:39
Ссама переменная крит секции имеет несколько полей, что они означают? Может быть для поиска конфликтов можно их проверять?

Вот как объявлена эта запись в Delphi:

_RTL_CRITICAL_SECTION = record
DebugInfo: PRTLCriticalSectionDebug;
LockCount: Longint;
RecursionCount: Longint;
OwningThread: THandle;
LockSemaphore: THandle;
Reserved: DWORD;
end;

mira
25.08.2011, 00:56
Ссама переменная крит секции имеет несколько полей, что они означают? Может быть для поиска конфликтов можно их проверять?

Вот как объявлена эта запись в Delphi:

_RTL_CRITICAL_SECTION = record
DebugInfo: PRTLCriticalSectionDebug;
LockCount: Longint;
RecursionCount: Longint;
OwningThread: THandle;
LockSemaphore: THandle;
Reserved: DWORD;
end;

ненадо там ниче проверять. опиратса на эти поля крайне не рекомендуетса (как и на саму структуру). кроме как большего гемора не получиш.
LockCount - это типа счетчик запираний (у секции поидеи 0 или 1)
OwningThread - ид потока вошедшего в секцию
LockSemaphore - помоему для случая какраз с трайэнтером (иначе не используетса)

xkor
25.08.2011, 01:18
LockCount - это типа счетчик запираний (у секции поидеи 0 или 1)
а мне кажется это для счётчика потоков ожидающих входа в секцию

Добавлено через 7 минут
а хотя...
The most important fields of the critical section structure are as follows:
In Microsoft Windows 2000, and Windows XP, the LockCount field indicates the number of times that any thread has called the EnterCriticalSection routine for this critical section, minus one. This field starts at -1 for an unlocked critical section. Each call of EnterCriticalSection increments this value; each call of LeaveCriticalSection decrements it. For example, if LockCount is 5, this critical section is locked, one thread has acquired it, and five additional threads are waiting for this lock.

The RecursionCount field indicates the number of times that the owning thread has called EnterCriticalSection for this critical section.

The EntryCount field indicates the number of times that a thread other than the owning thread has called EnterCriticalSection for this critical section.

When the first thread calls the EnterCriticalSection routine, the critical section's LockCount, RecursionCount, EntryCount and ContentionCount fields are all incremented by one, and OwningThread becomes the thread ID of the caller. EntryCount and ContentionCount are never decremented.
At this point, four different things can happen.

The owning thread calls EnterCriticalSection again. This will increment LockCount and RecursionCount. EntryCount is not incremented.
A different thread calls EnterCriticalSection. This will increment LockCount and EntryCount. RecursionCount is not incremented.
The owning thread calls LeaveCriticalSection. This will decrement LockCount (to -1) and RecursionCount (to 0), and will reset OwningThread to 0.
Another thread calls LeaveCriticalSection. This produces the same results as the owning thread calling LeaveCriticalSection -- it will decrement LockCount (to -1) and RecursionCount (to 0), and will reset OwningThread to 0.

When any thread calls LeaveCriticalSection, Windows decrements LockCount and RecursionCount. This feature has both good and bad aspects. It allows a device driver to enter a critical section on one thread and leave the critical section on another thread. However, it also makes it possible to accidentally call LeaveCriticalSection on the wrong thread, or to call LeaveCriticalSection too many times and cause LockCount to reach values lower than -1. This corrupts the critical section and causes all threads to wait indefinitely on the critical section.

Yegor
25.08.2011, 01:25
Да вот только как читать эти данные из рекорда крит секции. Вдруг они в этот момент обновляются.

mira
25.08.2011, 02:16
Да вот только как читать эти данные из рекорда крит секции. Вдруг они в этот момент обновляются.

завернуть еще в 1 крит секцию :p :D

а вообще ты слишком злопотребляеш многопоточкой, поток стоит создавать тогда когда есть острая необходимость. тут я ее невижу совсем :)

Yegor
25.08.2011, 02:39
Да у меня еще их немного. В клиенте L2 около 100 потоков.

xkor
25.08.2011, 10:26
Yegor, не иди по стопам корейцев)

mira
25.08.2011, 14:00
Да у меня еще их немного. В клиенте L2 около 100 потоков.

чем щитал :) ?
Если открыть список хендлов процесса их там совнем немного.

supernewbie
25.08.2011, 18:37
через оли было около 50 точно

Yegor
25.08.2011, 23:29
чем щитал :) ?
Если открыть список хендлов процесса их там совнем немного.

В диспетчере задач посмотрел. ProcessExplorer столько же показывает. Это касается только саркиофа. На фришках гораздо меньше, причем с каждым апдейтом фроста и хроник потоков все больше и больше.

mira
25.08.2011, 23:53
В диспетчере задач посмотрел. ProcessExplorer столько же показывает. Это касается только саркиофа. На фришках гораздо меньше, причем с каждым апдейтом фроста и хроник потоков все больше и больше.

а ну у нас фришка. там то понятно туча сторожевых потоков. они к игре отношение имеют весьма косвенное и синхронизация примитивная

xkor
26.08.2011, 00:08
туча сторожевых потоковвот только какой смысл больше чем в двух сторожевых потоках хоть убей не пойму...

mira
26.08.2011, 00:17
вот только какой смысл больше чем в двух сторожевых потоках хоть убей не пойму...

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

вон както вирус поймал. создал 2 процесса - один убил другой сразуже перепрятал его экзешник и переименовал и запустил снова. убил этот - прикрыл тот.

xkor
26.08.2011, 00:24
mira, ну дык для взаимоконтроля 3х потоков за глаза хватит...
а задачек там особых быть не должно для кучи потоков
в общем что то там в Ереване странное делают)