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.