I have a situation where a notify() 'can' be called before a wait().
I am trying to make a simulator to schedule its next event when I 'notify' him by sending him messages. So I have devised a wait->notify->scedule chain
void Broker::pause() { boost::unique_lock<boost::mutex> lock(m_pause_mutex); { std::cout << "pausing the simulation" << std::endl; m_cond_cnn.wait(lock); std::cout << "Simulation UNpaused" << std::endl; // the following line causes the current function to be called at // a later time, and a notify() can happen before the current function // is called again Simulator::Schedule(MilliSeconds(xxx), &Broker::pause, this); } } void Broker::messageReceiveCallback(std::string message) { boost::unique_lock<boost::mutex> lock(m_pause_mutex); { m_cond_cnn.notify_one(); } }
the problem here is that: there can be situations that a notify() is called before its wait() is called.
Is there a solution for such situation? thank you
Nothing stops you calling notify on an object that's not being wait ed by another thread.
In other words, if the notify() method is called when no other thread is waiting, notify() simply returns and the notification is lost. A thread that later executes the wait() method has to wait for another notification to occur.
If you need to call wait(), notify(), or notifyAll() from within a non-synchronized method, then you must first obtain a lock on the object's monitor. If you don't, an exception will be generated when an attempt is made to call the method in question.
If no threads are waiting in the waiting queue, then notify() and notifyAll() have no effect. Before calling the notify() or notifyAll() method of an object, a thread must own the lock of the object. Hence it must be in one of the object's synchronizedmethods or synchronized block.
Condition variables can hardly be used alone, if only because, as you noticed, they only wake the currently waiting threads. There's also the matter of spurious wake-ups (ie. the condition variable can sometimes wake up a thread without any corresponding notify
having been called). To work properly, condition variables usually need another variable to maintain a more reliable state.
To solve both those problems, in your case you just need to add a boolean flag:
boost::unique_lock<boost::mutex> lock(m_pause_mutex); while (!someFlag) m_cond_cnn.wait(lock); someFlag = false; //... boost::unique_lock<boost::mutex> lock(m_pause_mutex); someFlag = true; m_cond_cnn.notify_one();
I think that syam's answer is fine in general but in your specific case where you seem to be using ns-3, I would suggest instead that you restructure your code to use the right primitives in ns-3:
Keep in mind that the ns-3 API is not thread safe in general. The only ns-3 API that is thread-safe is ns3::Simulator::ScheduleWithContext. I can't stress out how important it is to not use any other API available in the ns-3:: namespace from a thread that is not the main thread.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With