День добрый!
При портировании одной библиотеки из UNIX в Windows столкнулся с тем, что некоторый кусок кода корректно работает в UNIX и не работает в Windows. Подозрение пало на функцию boost::condition::timed_wait()... Чтобы не засорять форум, я написал маленький тестик:
Класс AsyncQueue — простенький контейнер для которого определены 2 операции — push() и timed_pop(). Фактически в контейнере ничего не хранится (это же тест как-никак , а просто ведется счетчик количества элементов (m_counter). Для проверки всего этого дела создается дополнительный поток и с него выполняется операция push(). Основной поток имитирует получение данных из очереди.
Внимание вопрос: почему иногда генерируется исключение out_of_range() при вызове timed_pop()? Получается, что boost::condition::timed_wait() иногда возвращает true даже тогда, когда не было вызова wait_one()? Или я туплю?...
Здравствуйте, syomin, Вы писали:
S>День добрый! S>При портировании одной библиотеки из UNIX в Windows столкнулся с тем, что некоторый кусок кода корректно работает в UNIX и не работает в Windows. Подозрение пало на функцию boost::condition::timed_wait()... Чтобы не засорять форум, я написал маленький тестик:
S> void timed_pop(const xtime &time) S> { S> mutex::scoped_lock lock(m_mutex);
S> if(m_counter) { S> m_counter--; S> return; S> }
S> if(!m_condition.timed_wait(lock, time)) return;
S> if(!m_counter) throw out_of_range("oops...");
S> m_counter--; S> }
S>Внимание вопрос: почему иногда генерируется исключение out_of_range() при вызове timed_pop()? Получается, что boost::condition::timed_wait() иногда возвращает true даже тогда, когда не было вызова wait_one()? Или я туплю?...
s/wait_one/notify_one/
Именно так. Существуют так называемые spurious wakeups, т.е. когда функция wait возвращается, но условие ожидания не выполнено.
Из-за этого конструкция
Здравствуйте, Elifant, Вы писали:
E>Именно так. Существуют так называемые spurious wakeups, т.е. когда функция wait возвращается, но условие ожидания не выполнено. E>Из-за этого конструкция
Занятно, занятно... здесь одна из первых ссылок googla по запросу spurious wakeups, она немного проясняет причины такого поведения.
Хотя совершенно непонятно, как это происходит на Win32? Как они вообще добились такого поведения, что происходят spurious wakeups? Ведь в Win32 такого нет, т.е. если уж мы закончили ждать на объекте, значит его кто-то перевёл в свободное состояние (или я совсем от жизни отстал).
Здравствуйте, remark, Вы писали:
R>Хотя совершенно непонятно, как это происходит на Win32? Как они вообще добились такого поведения, что происходят spurious wakeups? Ведь в Win32 такого нет, т.е. если уж мы закончили ждать на объекте, значит его кто-то перевёл в свободное состояние (или я совсем от жизни отстал).
В Win32 нет собственно condition'а, он эмулируется затейливой связкой из нескольких мьютексов и, кажется, эвента.
Когда возникает гонка между пробуждением от ожидания и извещением — то, в принципе, возможны две ситуации:
— извещение теряется — тогда следующего пробуждения не будет, и поток повиснет
— закладывается лишнее извещение — тогда следующее пробуждение будет ложным
Поскольку ложные пробуждения "входят в стоимость тура", второй сценарий считается безопасным.
Ну и кроме того, пробуждение может быть ложным из-за того, что после отправки извещения условие инвалидировалось до пробуждения. В простых ситуациях, как у тебя, такое помыслить невозможно; но в общем случае запросто.
Поэтому ожидание в цикле — единственно верный подход.