Почему boost::timed_wait всегда блокируется при вызове с абсолютным временем?

Я пытаюсь понять, как использовать timed_wait. Я нашел только несколько примеров (здесь и здесь), и у меня возникла проблема при вызове с абсолютным временем. Следующий код является упрощенным примером, на самом деле все это происходит внутри класса, поэтому я подумал, что будет проще проверить мой предикат вручную, вместо того, чтобы использовать какую-то привязку и передавать ее в timed_wait.

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread.hpp>
#include <iostream>

bool done = false;
boost::mutex mutex;
boost::thread waitingThread;
boost::condition_variable cond;

void wait(boost::posix_time::time_duration dt){
    boost::mutex::scoped_lock lock(mutex);
    boost::system_time x = boost::posix_time::microsec_clock::local_time() + dt;
    bool timedOut = false;
    while((done == false) && (x > boost::posix_time::microsec_clock::local_time())) {
        timedOut = ! cond.timed_wait(lock,x);
    }
    if (timedOut){ std::cout << "timeout\n"; }
    else         { std::cout << "success\n"; }
}

void wait2(boost::posix_time::time_duration dt){
    boost::mutex::scoped_lock lock(mutex);
    bool timedOut = ! cond.timed_wait(lock,dt);
    if (timedOut){ std::cout << "timeout\n"; }
    else         { std::cout << "success\n"; }

}

void test(){
    //boost::thread waiter = boost::thread(wait,boost::posix_time::milliseconds(50));
    boost::thread waiter = boost::thread(wait2,boost::posix_time::milliseconds(50));
    boost::this_thread::sleep(boost::posix_time::milliseconds(2000));
}

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

cond.timed_wait(lock,dt, ?bind?(&Foo::isDone,this));

но тогда я не уверен на 100%, что ложное пробуждение заставит timed_wait вернуть true (в этом случае мой while (x > local_time()) будет излишним.


person 463035818_is_not_a_number    schedule 07.06.2017    source источник


Ответы (1)


Используйте boost::get_system_time() + dt, основанный на UTC, вместо local_time() + dt, который настраивается с учетом часового пояса, потому что wait_lock(...) использует boost::get_system_time() для сравнения текущего времени с целевым абсолютным временем.

Следующий пример иллюстрирует проблему:

int main() {
    std::cout << "System time: " 
              << boost::get_system_time() << std::endl;
    std::cout << "Local time: " 
              << boost::posix_time::microsec_clock::local_time() << std::endl;
}

Выход:

System time: 2017-Jun-07 08:47:58.836677
Local time: 2017-Jun-07 11:47:58.837003

Таким образом, ваша функция wait(), основанная на абсолютном времени, блокируется только на несколько часов, определяемых смещением часового пояса вашего компьютера, а не навсегда.

person dekin    schedule 07.06.2017