реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> WinAPI - Event`ы работают не корректно
megajohn
сообщение Feb 10 2014, 14:14
Сообщение #1


Профессионал
*****

Группа: Свой
Сообщений: 1 080
Регистрация: 16-11-04
Из: СПб
Пользователь №: 1 143



нужно организовать алгоритм:
три задачи 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

как лечится ?


--------------------
Марс - единственная планета, полностью населенная роботами (около 7 штук).
Go to the top of the page
 
+Quote Post
SM
сообщение Feb 10 2014, 14:22
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881



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

PulseEvent это вообще глюкогенератор - функция, позволяющая глюкнуть евентом sm.gif
Go to the top of the page
 
+Quote Post
megajohn
сообщение Feb 10 2014, 14:27
Сообщение #3


Профессионал
*****

Группа: Свой
Сообщений: 1 080
Регистрация: 16-11-04
Из: СПб
Пользователь №: 1 143



так тоже лажа:
Код
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 );
}



--------------------
Марс - единственная планета, полностью населенная роботами (около 7 штук).
Go to the top of the page
 
+Quote Post
SM
сообщение Feb 10 2014, 14:53
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881



Нужно ДВА евента - 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 );
}
Go to the top of the page
 
+Quote Post
megajohn
сообщение Feb 10 2014, 15:35
Сообщение #5


Профессионал
*****

Группа: Свой
Сообщений: 1 080
Регистрация: 16-11-04
Из: СПб
Пользователь №: 1 143



Цитата(SM @ Feb 10 2014, 18:53) *
Нужно ДВА евента - events_t1a_start и events_t1b_start (оба с авторезетом) и им в t2 делать SetEvent обоим


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

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




--------------------
Марс - единственная планета, полностью населенная роботами (около 7 штук).
Go to the top of the page
 
+Quote Post
SM
сообщение Feb 10 2014, 15:52
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881



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

Что касается двух ResetEvent в двух тредах, так то понятно и без описания, что первый тред может сбросить event еще до того, как проснется второй.
Go to the top of the page
 
+Quote Post
megajohn
сообщение Feb 10 2014, 21:04
Сообщение #7


Профессионал
*****

Группа: Свой
Сообщений: 1 080
Регистрация: 16-11-04
Из: СПб
Пользователь №: 1 143



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


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

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

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

ссылка


--------------------
Марс - единственная планета, полностью населенная роботами (около 7 штук).
Go to the top of the page
 
+Quote Post
SM
сообщение Feb 10 2014, 21:17
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881



Цитата(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.

То есть ЛЮБОЕ КОЛИЧЕСТВО ожидающих тредов МОЖЕТ БЫТЬ запущено. А может и не быть, и вовсе не обязательно, что все... любое количество это любое... может и одна, а может и две, а может и ни одной, если слишком быстро его сбросить... Так что все там корректно работает и в рамках документации.
Go to the top of the page
 
+Quote Post
megajohn
сообщение Feb 11 2014, 07:53
Сообщение #9


Профессионал
*****

Группа: Свой
Сообщений: 1 080
Регистрация: 16-11-04
Из: СПб
Пользователь №: 1 143



Цитата(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 еще до того, как уйдет в ожидание и уснёт второй.


--------------------
Марс - единственная планета, полностью населенная роботами (около 7 штук).
Go to the top of the page
 
+Quote Post
SM
сообщение Feb 11 2014, 08:06
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881



Цитата(megajohn @ Feb 11 2014, 11:53) *
чой-та я не согласен

Да я тоже не согласен. Но микрософт, гад, забыл спросить моего согласия, делая свои евенты такими, как в их описании sm.gif
Go to the top of the page
 
+Quote Post
kolobok0
сообщение Feb 12 2014, 04:40
Сообщение #11


практикующий тех. волшебник
*****

Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417



Цитата(megajohn @ Feb 11 2014, 11:53) *
чой-та я не согласен...


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

очень часто народ пишет например старт ниток без синхронной фазы. как следствие - при ударных нагрузках временные параметры текут.
и конкретно текут. без фаз синхронизации логика расползается и перестаёт(как правило) корректно работать.
Go to the top of the page
 
+Quote Post
megajohn
сообщение Feb 12 2014, 08:33
Сообщение #12


Профессионал
*****

Группа: Свой
Сообщений: 1 080
Регистрация: 16-11-04
Из: СПб
Пользователь №: 1 143



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


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

кстати, кому из начинающих хочется поигратся с потоками и эвентами, то вот готовый тестовый проектикПрикрепленный файл  test_ev.rar ( 10.36 килобайт ) Кол-во скачиваний: 50


--------------------
Марс - единственная планета, полностью населенная роботами (около 7 штук).
Go to the top of the page
 
+Quote Post
kolobok0
сообщение Feb 12 2014, 12:51
Сообщение #13


практикующий тех. волшебник
*****

Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417



Цитата(megajohn @ Feb 12 2014, 12:33) *
..синхронизацю по запуску потоков применяю...


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

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

Сообщение отредактировал kolobok0 - Feb 12 2014, 12:54
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 15:02
Рейтинг@Mail.ru


Страница сгенерированна за 0.01475 секунд с 7
ELECTRONIX ©2004-2016