简体   繁体   中英

Notify condition variable from boost::timed_wait only works once

I want to use boost::timed_wait to wait for an event or to timeout after 5 seconds. My problem is that my timed_wait only accepts the notification for the first time.

To be more precise:

I have some kind of little state machine. It does nothing more than just dispatch some Command asynchronously and then check if it was successfully. This means after dispatching the command my state machine calls m_Condition.timed_wait(lock,timeout) . ( m_Condition is a member variable with the type boost::condition_variable ).

Now if this asynchronous call was successfull it shall call a callback function which notifies m_Condition so I know everything went OK. When the command failed it doesn't call the callback function and so my timed_wait should time out. So the callback function does nothing more and nothing less than calling m_Condition.notify_all() .

The problem is that this only works the first time. This means, after the first time notify_all() has been called it doesn't work with that condition variable again. I checked at my callback and it always calls notify_all() again but the timed_wait just times out.

Maybe some example code to make it a bit clearer:

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();
}

So what can I do now? Is it not possible to use the condition_variable multiple times? Or do I need to reset it somehow? Any suggestions are welcome!

No, you do not have to reset the condition variable, and yes it works multiple times.

I believe what you are seeing is a deadlock, rather than failure when waiting the second time on m_condition. When you call timed_wait() in stateMachine() your mutex will be unlocked, and it is re-locked when timed_wait() returns. I'm guessing that in the missing code which follows the wait you are calling callbackEvent(). That method attempts to lock the mutex, but it cannot because (a) it is already locked in the caller (stateMachine()) and (b) boost::mutex isn't re-entrant. You could try using eg recursive_mutex instead.

Okay, not the brightest hour for me I actually solved the problem. The above posted code is compiling and works as intended. The actual problem lied within the handling of Event or Timeout. Since the stuff that happened there is absolutely unrelated to the timed_wait I guess I don't need to explain it here. So this question can be closed.

UPDATE:

Of course the above code won't work since the lack of a dispatch method. Just for the sake of it I am gonna mention it here: For testing purposes I just create an Object of myClass_A in my main function, start the state machine and then call the callbackEvent from my main function. This actually works!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM