【问题标题】:what if notify() is called before wait()?如果在 wait() 之前调用 notify() 会怎样?
【发布时间】:2013-07-10 05:18:19
【问题描述】:

我有一种情况,即可以在 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() 的情况。

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

【问题讨论】:

    标签: c++ boost synchronization condition-variable ns-3


    【解决方案1】:

    条件变量很难单独使用,因为正如您所注意到的,它们只会唤醒当前等待的线程。还有虚假唤醒的问题(即条件变量有时可以唤醒线程而没有调用任何相应的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();
    

    【讨论】:

    • 这样的“带标志的条件变量”只是一个最大级别为1的信号量,我说得对吗?
    • 我想知道为什么 C++11 和 pthreads 称它为“条件变量”,尽管它是完全无状态的并且像一个裸信号/事件一样工作,而 WinAPI 称它为“事件”,而它在那里工作就像一个同步的布尔标志。不应该反过来吗?
    • 那个标志不是必须是std::atomic吗?
    • @kroiz 在这种情况下,否:访问受互斥锁保护。如果某些代码在没有先锁定互斥锁的情况下访问它,则它需要是原子的。
    【解决方案2】:

    我认为 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 从非主线程的线程是多么重要。

    【讨论】:

      猜你喜欢
      • 2012-05-10
      • 2013-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-20
      • 1970-01-01
      相关资源
      最近更新 更多