what if notify() is called before wait()?
Asked Answered
Y

2

29

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

Youmans answered 10/7, 2013 at 5:18 Comment(1)
See also: Is there a notify_one ( ) queue?Hyoscyamine
S
27

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();
Sesquiplane answered 10/7, 2013 at 5:36 Comment(4)
Am I right that such "conditional variable with flag" is just a semaphore with the maximum level of 1?Peers
I wonder why C++11 and pthreads call it "condition variables", although it is completely stateless and works like a bare signal/event, and WinAPI calls it "events", while it works there like a synchronized boolean flag. Shouldn't it be vice versa?Afterburning
Isn't that flag needs to be std::atomic<bool>?Charteris
@Charteris In this case no: the access is protected by the mutex. It would need to be atomic if some code accessed it without locking the mutex first.Sesquiplane
T
3

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:

  1. I suspect that you use one of the ns-3 realtime simulator implementations. Good.
  2. Schedule a keeplive event for the 0.1s to make sure that the simulator keeps running (it will top running when there are no events left).
  3. Optionally, use a boolean in this keepalive event to check if you should reschedule the keepalive event or call Simulator::Stop.
  4. Create a thread to run the simulator mainloop with Simulator::Run(). The simulator will sleep until the next scheduled event is supposed to expire or until a new event is externally scheduled
  5. Use Simulator::ScheduleWithContext to schedule an event externally from another thread.

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.

Tiein answered 15/7, 2013 at 8:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.