Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: WinAPI - Event`ы работают не корректно
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
megajohn
нужно организовать алгоритм:
три задачи t1a t1b t2 ( в WinApi это Thread но сути не меняет )
нужно чтобы t1a и t1b выполнили некое действие, выставили готовность чтобы уйти в ожидание и дать управление задаче t2, задача t2 выполняет свое действие, приостанавливает свою работу и разрешает работу t1a и t1b
и снова по кругу

написал следующее (псевдокод):
Код
HANDLE events_t1_rdy[2] = { 0 };
HANDLE events_t2_rdy  = { 0 };

events_t1_rdy[0] = CreateEvent( NULL, FALSE, FALSE, NULL ); // с автосбросом
events_t1_rdy[1] = CreateEvent( NULL, FALSE, FALSE, NULL ); // с автосбросом
events_t2_rdy    = CreateEvent( NULL, TRUE,  FALSE, NULL ); // с ручным сбросом

t1a()
{
    t1a_todo();
    SetEvent( events_t1_rdy[0] );
    DWORD dwEvent = WaitForSingleObject( events_t2_rdy, 5000 );
    assert( dwEvent == WAIT_OBJECT_0 );
}

t1b()
{
    t1b_todo();
    SetEvent( events_t1_rdy[1] );
    DWORD dwEvent = WaitForSingleObject( events_t2_rdy, 5000 );
    assert( dwEvent == WAIT_OBJECT_0 );
}

t2()
{
    DWORD dwEvent = WaitForMultipleObjects( 2, events_t1_rdy, TRUE, 5000 );
    assert( dwEvent == WAIT_OBJECT_0 );
    t2_todo();
    PulseEvent( events_t2_rdy );
}


дык вот, один раз в 100тысяч - милллион раз, одна задача (t1a или t1b ) не получает что t2 готов и ловлю dwEvent = 258 = 0x102 = TIMEOUT

как лечится ?
SM
двумя ивентами с автосбросом на разрешение t1a и t1b по отдельности, устанавливаемых подряд по SetEvent в t2.

PulseEvent это вообще глюкогенератор - функция, позволяющая глюкнуть евентом sm.gif
megajohn
так тоже лажа:
Код
t1a()
{
    t1a_todo();
    SetEvent( events_t1_rdy[0] );
    DWORD dwEvent = WaitForSingleObject( events_t2_rdy, 5000 );
    assert( dwEvent == WAIT_OBJECT_0 );
              ResetEvent( events_t2_rdy );
}

t1b()
{
    t1b_todo();
    SetEvent( events_t1_rdy[1] );
    DWORD dwEvent = WaitForSingleObject( events_t2_rdy, 5000 );
    assert( dwEvent == WAIT_OBJECT_0 );
              ResetEvent( events_t2_rdy );
}

t2()
{
    DWORD dwEvent = WaitForMultipleObjects( 2, events_t1_rdy, TRUE, 5000 );
    assert( dwEvent == WAIT_OBJECT_0 );
    t2_todo();
    SetEvent( events_t2_rdy );
}

SM
Нужно ДВА евента - events_t1a_start и events_t1b_start (оба с авторезетом) и им в t2 делать SetEvent обоим

CODE

t1a()
{
t1a_todo();
SetEvent( events_t1_rdy[0] );
DWORD dwEvent = WaitForSingleObject( events_t1a_start, 5000 );
assert( dwEvent == WAIT_OBJECT_0 );
}

t1b()
{
t1b_todo();
SetEvent( events_t1_rdy[1] );
DWORD dwEvent = WaitForSingleObject( events_t1b_start, 5000 );
assert( dwEvent == WAIT_OBJECT_0 );
}

t2()
{
DWORD dwEvent = WaitForMultipleObjects( 2, events_t1_rdy, TRUE, 5000 );
assert( dwEvent == WAIT_OBJECT_0 );
t2_todo();
SetEvent( events_t1a_start );
SetEvent( events_t1b_start );
}
megajohn
Цитата(SM @ Feb 10 2014, 18:53) *
Нужно ДВА евента - events_t1a_start и events_t1b_start (оба с авторезетом) и им в t2 делать SetEvent обоим


так то работает.

А где можно почитать, что в WinAPI один Event не умеет правильно будить два потока ?


SM
Не знаю, где почитать. А про PulseEvent так в MSDN прямо написано, что это глюк, а не функция, PulseEvent is unreliable and should not be used by new applications

Что касается двух ResetEvent в двух тредах, так то понятно и без описания, что первый тред может сбросить event еще до того, как проснется второй.
megajohn
Цитата(SM @ Feb 10 2014, 19:52) *
Что касается двух ResetEvent в двух тредах, так то понятно и без описания, что первый тред может сбросить event еще до того, как проснется второй.


я исходил из того, что оба потока были в состоянии WAIT/SUSPEND
в момент установки события events_t2_rdy шедуллер бы увидел список из двух ожидающих потоков и перевел оба в RUNNABLE. А уж дальше пофиг какой что сбросит

Значит в винде не так

P.S. Нашел кстати, откуда я вычитал, что одно событие может запускать несколько потоков
Цитата
Событие с ручным управлением подобно стартовому пистолету. Как только оно будет установлено в сигнализирующее состояние, будут освобождены сразу все потоки.

ссылка
SM
Цитата(megajohn @ Feb 11 2014, 01:04) *
Значит в винде не так


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

И вообще, не читайте по утрам советских газет... В MSDN английским по белому про SetEvent:

The state of a manual-reset event object remains signaled until it is set explicitly to the nonsignaled state by the ResetEvent function. Any number of waiting threads, or threads that subsequently begin wait operations for the specified event object by calling one of the wait functions, can be released while the object's state is signaled.

То есть ЛЮБОЕ КОЛИЧЕСТВО ожидающих тредов МОЖЕТ БЫТЬ запущено. А может и не быть, и вовсе не обязательно, что все... любое количество это любое... может и одна, а может и две, а может и ни одной, если слишком быстро его сбросить... Так что все там корректно работает и в рамках документации.
megajohn
Цитата(SM @ Feb 11 2014, 01:17) *
То есть ЛЮБОЕ КОЛИЧЕСТВО ожидающих тредов МОЖЕТ БЫТЬ запущено. А может и не быть, и вовсе не обязательно, что все... любое количество это любое... может и одна


чой-та я не согласен

вообщем, методом проб и ошибок вроде понял в чем трабла.

после освобождения t2 она так быстро делает todo и выставляет event_t2 что t1a просто не успевает дойти до ожидания, а другая t1b успевает и сбрасывает событие
Нажмите для просмотра прикрепленного файла

Вообщем, сделал по вашему первому посту, работает и ладно

UPD: проблема, в том что применена связка команд SetEvent( events_t1_rdy[0] ) и WaitForSingleObject( events_t2_rdy, 5000 ); и эта связка не атомарна.
Тут напрашивается SignalObjectAndWait но оказывается, что тоже не атомарный =(

UPD2:
Цитата(SM @ Feb 10 2014, 19:52) *
Что касается двух ResetEvent в двух тредах, так то понятно и без описания, что первый тред может сбросить event еще до того, как проснется второй.

скорее всего, что первый тред может сбросить event еще до того, как уйдет в ожидание и уснёт второй.
SM
Цитата(megajohn @ Feb 11 2014, 11:53) *
чой-та я не согласен

Да я тоже не согласен. Но микрософт, гад, забыл спросить моего согласия, делая свои евенты такими, как в их описании sm.gif
kolobok0
Цитата(megajohn @ Feb 11 2014, 11:53) *
чой-та я не согласен...


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

очень часто народ пишет например старт ниток без синхронной фазы. как следствие - при ударных нагрузках временные параметры текут.
и конкретно текут. без фаз синхронизации логика расползается и перестаёт(как правило) корректно работать.
megajohn
Цитата(kolobok0 @ Feb 12 2014, 08:40) *
очень часто народ пишет например старт ниток без синхронной фазы. как следствие - при ударных нагрузках временные параметры текут.
и конкретно текут. без фаз синхронизации логика расползается и перестаёт(как правило) корректно работать.


синхронизацю по запуску потоков применяю

кстати, кому из начинающих хочется поигратся с потоками и эвентами, то вот готовый тестовый проектикНажмите для просмотра прикрепленного файла
kolobok0
Цитата(megajohn @ Feb 12 2014, 12:33) *
..синхронизацю по запуску потоков применяю...


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

ну и второе маленьчкое замечание..
если пишите на си плас плас - сделайте лаконичный и просто класс для порождения нитки. при грамотной упаковке решаться сразу такие вещи как
передача различных по типу данных в нитку, вопросы синхронизации старт-стопа нитки, ну и кучка ышо плюшечек нароете по дороге...
вот этот класец Вам многое поможет потом по жизни. поверьте реализация в библиотеках - всякие бусты и ко = не всегда ровная sm.gif))
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.