Уведомить условную переменную из boost :: timed_wait работает только один раз - PullRequest
0 голосов
/ 28 марта 2012

Я хочу использовать boost::timed_wait для ожидания события или тайм-аута через 5 секунд. Моя проблема в том, что мой timed_wait принимает уведомление только в первый раз.

Чтобы быть более точным:

У меня есть какой-то маленький конечный автомат. Он не делает ничего, кроме как просто отправляет некоторую Команду асинхронно и затем проверяет, была ли она успешной. Это означает, что после отправки команды мой конечный автомат вызывает m_Condition.timed_wait(lock,timeout). (m_Condition является переменной-членом типа boost::condition_variable).

Теперь, если этот асинхронный вызов был успешным, он должен вызвать функцию обратного вызова, которая уведомляет m_Condition, поэтому я знаю, что все прошло нормально. Когда команда не выполняется, она не вызывает функцию обратного вызова, поэтому мой timed_wait должен истечь. Таким образом, функция обратного вызова не делает ничего больше и не меньше, чем вызывает m_Condition.notify_all().

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

Может быть, какой-нибудь пример кода, чтобы сделать его немного понятнее:

myClass_A.hpp

class myClass_A
{
public:
    void runStateMachine();                 // Starts the state machine
    void callbackEvent();                   // Gets called when Async Command was successful
private:
    void stateMachine();                    // Contains the state machine
    void dispatchAsyncCommand();            // Dispatches an Asynchronous command
    boost::thread m_Thread;                 // Thread for the state machine
    boost::condition_variable m_Condition;  // Condition variable for timed_wait
    boost::mutex m_Mutex;                   // Mutex
};

myClass_A.cpp

void myClass_A::runStateMachine()
{
     m_Thread = boost::thread(boost::bind(&myClass_A,this));
}
void myClass_A::dispatchAsyncCommand()
{
     /* Dispatch some command Async and then return */
     /* The dispatched Command will call callbackEvent() when done */
}
void myClass_A::stateMachine()
{
    boost::mutex::scoped_lock lock(m_Mutex);
    while(true)
    {
        dispatchAsynCommand();
        if(!m_Condition.timed_wait(lock, boost::posix_time::milliseconds(5000)))
        {
            // Timeout
        }
        else
        {
            // Event
        }
    }
}
void myClass_A::callbackEvent()
{
    boost::mutex::scoped_lock lock(m_Mutex);
    m_Condition.notify_all();
}

Так что же мне теперь делать? Разве невозможно использовать условие_ переменную несколько раз? Или мне нужно как-то его сбросить? Любые предложения приветствуются!

Ответы [ 2 ]

0 голосов
/ 28 марта 2012

Ладно, не самый яркий час для меня, я действительно решил проблему. Приведенный выше код компилируется и работает как задумано. Фактическая проблема заключалась в обработке события или тайм-аута. Поскольку то, что там произошло, абсолютно не связано с timed_wait, я думаю, мне не нужно здесь это объяснять. Так что этот вопрос можно закрыть.

UPDATE:

Конечно, приведенный выше код не будет работать из-за отсутствия метода отправки. Просто ради этого я упомяну это здесь: для целей тестирования я просто создаю объект myClass_A в моей главной функции, запускаю конечный автомат и затем вызываю callbackEvent из моей основной функции. Это на самом деле работает!

0 голосов
/ 28 марта 2012

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

Я считаю, что вы видите тупик, а не сбой при повторном ожидании в m_condition. Когда вы вызываете timed_wait () в stateMachine (), ваш мьютекс будет разблокирован, и он будет снова заблокирован, когда timed_wait () вернется. Я предполагаю, что в отсутствующем коде, который следует за ожиданием, вы вызываете callbackEvent (). Этот метод пытается заблокировать мьютекс, но он не может этого сделать, потому что (a) он уже заблокирован в вызывающей стороне (stateMachine ()) и (b) boost :: mutex не возвращается Вы можете попробовать использовать, например, вместо recursive_mutex.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...