boost — timed_wait не ждет

Я запускаю следующий код на ОС Linux + процессор ARM + boost 1.51. Но код не работает должным образом, и вызов timed_wait() возвращается немедленно.

#include <boost/thread/condition.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/thread/mutex.hpp>
#include <iostream>

using namespace std;

int main()
{
     boost::mutex mutex_;
     boost::mutex::scoped_lock lock( mutex_ );

     boost::xtime xt;
     boost::condition condition;

     // wait for one second or wait on lock
     boost::xtime_get(&xt, boost::TIME_UTC_);

     xt.sec += 1;

     cout << "Before 1 second wait" << endl;
     condition.timed_wait(lock, xt);
     cout << "After 1 second wait" << endl;

     return 0;
}

В других системах с тем же процессором ARM, но другой версией Linux + glibc + такими же библиотеками boost 1.51 код работает нормально и ждет 1 секунду.

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

strace из системы, где код работает:

write(1, "Before 1 second wait\n", 21Before 1 second wait)  = 21
futex(0xb6fbf0dc, FUTEX_WAKE_PRIVATE, 2147483647) = 0
clock_gettime(CLOCK_REALTIME, {1438150496, 732211544}) = 0
futex(0xbef07a44, FUTEX_WAIT_PRIVATE, 1, {0, 998193456}) = -1 ETIMEDOUT (Connection timed out)
futex(0xbef07a28, FUTEX_WAKE_PRIVATE, 1) = 0
write(1, "After 1 second wait\n", 20After 1 second wait)   = 20

strace из системы, код которой НЕ работает:

    write(1, "Before 1 second wait\n", 21Before 1 second wait)  = 21
    futex(0xb6fc90dc, FUTEX_WAKE_PRIVATE, 2147483647) = 0
    clock_gettime(CLOCK_REALTIME, {1438150407, 134963583}) = 0
    futex(0xbe9be988, FUTEX_WAKE_PRIVATE, 1) = 0
    write(1, "After 1 second wait\n", 20After 1 second wait)   = 20

Есть ли изменение ядра/glibc, необходимое для работы этого кода?


person Bob    schedule 29.07.2015    source источник
comment
Попробуйте predicate версию timed_wait. Возможно, это ложное пробуждение, заставляющее просыпаться рано. condition.timed_wait(lock, boost::posix_time::milliseconds(1000), f);, где f определяется как bool f(void) { return false; }.   -  person Tsyvarev    schedule 29.07.2015
comment
Спасибо за предложение. Но предикат не помогает. Я думаю, что вызов futex() более низкого уровня по какой-то причине не выполняется, как я уже упоминал в своем вопросе.   -  person Bob    schedule 30.07.2015
comment
Хм, кажется, ваша установка Boost по какой-то причине не работает. Он ведет себя так, как будто тайм-аут уже прошел, поэтому нет необходимости вызывать futex для ожидания по условию. Вы можете отследить вызов boost::xtime_get(), посмотреть отметку времени, которую он возвращает, и сравнить ее с той, что была возвращена clock_gettime при вызове condition.timed_wait().   -  person Tsyvarev    schedule 30.07.2015


Ответы (2)


Вместо того, чтобы возиться с часами при использовании тайм-аутов, почему бы не использовать реальный тайм-аут?

condition.timed_wait(lock,boost::posix_time::milliseconds(1000))

Это предотвращает всевозможные странные проблемы.

person Mark Jansen    schedule 29.07.2015
comment
Вызов timed_wait принимает абсолютное значение времени, до которого он будет ждать. На самом деле, я попробовал ваше предложение, и результат тот же. - person Bob; 29.07.2015

Я смог понять, что происходит, изменив тайм-ауты с 1 на 100.

Я передал тайм-аут в качестве аргумента программе и использовал

xt.sec += timeout;

Когда тайм-аут выше 26, программа ждала (тайм-аут - 26) секунд. Другими словами, программа ждет 1 секунду: если таймаут 27, 2 секунды: если таймаут 28 и так далее...

Смещение 26 происходит от количества високосных секунд. Если информация о часовом поясе в системе содержит информацию о дополнительных секундах, то мы наблюдаем эту проблему. Если я изменю информацию о часовом поясе (/etc/localtime) так, чтобы она указывала на файл zoneinfo, в котором нет информации о дополнительных секундах, API-интерфейс boost будет работать правильно.

person Bob    schedule 30.07.2015
comment
Я нашел очень похожий вопрос SO: stackoverflow.com /вопросы/2784639/. Его автор столкнулся с той же проблемой с boost 1.38 на RedHat. На самом деле, документация Boost отмечает, что использование времени UTC для временных меток future не очень хорошая идея: именно из-за високосных секунд. boost::chrono::seconds(1) кажется более подходящим для интервала ожидания. - person Tsyvarev; 30.07.2015
comment
Спасибо за комментарий и использование класса хроно. Я не осознавал, что это проблема второго плана, когда я впервые отправил запрос. - person Bob; 11.08.2015