23

我有一种情况,在 wait() 之前可以调用 notify()。

当我通过向他发送消息“通知”他时,我正在尝试制作一个模拟器来安排下一个事件。所以我设计了一个等待->通知->调度链

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

这里的问题是:可能存在在调用其 wait() 之前调用 notify() 的情况。

这种情况有解决办法吗?谢谢你

4

2 回答 2

21

条件变量几乎不能单独使用,因为正如您所注意到的,它们只会唤醒当前等待的线程。还有虚假唤醒的问题(即条件变量有时可以唤醒一个线程而没有任何相应notify的调用)。为了正常工作,条件变量通常需要另一个变量来保持更可靠的状态。

要解决这两个问题,在您的情况下,您只需要添加一个布尔标志:

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();
于 2013-07-10T05:36:56.743 回答
3

我认为 syam 的回答总体上很好,但在您似乎使用 ns-3 的特定情况下,我建议您改组代码以在 ns-3 中使用正确的原语:

  1. 我怀疑您使用的是 ns-3 实时模拟器实现之一。好的。
  2. 为 0.1 秒安排一个 keeplive 事件,以确保模拟器继续运行(当没有事件剩余时它将运行到顶)。
  3. 或者,在此 keepalive 事件中使用布尔值来检查您是否应该重新安排 keepalive 事件或调用 Simulator::Stop。
  4. 使用 Simulator::Run() 创建一个线程来运行模拟器主循环。模拟器将休眠,直到下一个计划的事件应该到期或直到新的事件被外部安排
  5. 使用 Simulator::ScheduleWithContext 从另一个线程外部调度事件。

请记住,ns-3 API 通常不是线程安全的。唯一一个线程安全的 ns-3 API 是 ns3::Simulator::ScheduleWithContext。我不能强调不使用ns-3:: 命名空间中任何其他 API 的重要性,因为它不是主线程。

于 2013-07-15T08:01:23.350 回答