【问题标题】:Notify condition variable from boost::timed_wait only works once从 boost::timed_wait 通知条件变量只工作一次
【发布时间】:2012-03-28 09:59:59
【问题描述】:

我想使用boost::timed_wait 等待事件或在 5 秒后超时。我的问题是我的timed_wait 只接受第一次通知。

更准确地说:

我有某种小型状态机。它只是异步发送一些命令,然后检查它是否成功。这意味着在发送命令后,我的状态机调用m_Condition.timed_wait(lock,timeout)。 (m_Condition 是一个类型为 boost::condition_variable 的成员变量)。

现在,如果这个异步调用成功,它会调用一个回调函数来通知m_Condition,所以我知道一切正常。当命令失败时,它不会调用回调函数,所以我的timed_wait 应该超时。所以回调函数无非就是调用m_Condition.notify_all()

问题是这只能在第一次工作。这意味着,在第一次调用 notify_all() 之后,它不再适用于该条件变量。我检查了我的回调,它总是再次调用notify_all(),但timed_wait 只是超时。

也许一些示例代码使其更清晰:

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

那我现在能做什么?不能多次使用condition_variable吗?还是我需要以某种方式重置它?欢迎提出任何建议!

【问题讨论】:

  • 不是答案,因为我不确定您的代码中发生了什么,但条件变量不仅仅是信号,它们应该用于表示共享条件的变化。请参阅此示例:justsoftwaresolutions.co.uk/threading/…
  • 在您的代码中,条件可能是繁忙标志,因此 stateMachine 可能具有“busy = true; while (busy && !rc) { rc = m_Condition.timed_wait(...); }”
  • @stefaanv 感谢您的建议。我读了你发布的那篇文章,好吧,也许我使用timed_wait 不是为了通常的预期目的,但它仍然应该做交易。实际上他们在那里使用的实现和我的完全一样。对于您的第二条评论:那个忙碌的旗帜应该做什么?我的意思是我的问题是我的timed_wait 仅在第一次调用后返回超时和false 的返回值。我可以打电话给notify_all()我想要的一切..不会改变任何东西:/
  • 实际上,我看不出它在您的代码中可能失败的地方,因为 notify_all 只能在互斥锁被锁定时调用,这意味着另一个线程处于 timed_wait 中,但仍然没有那么困难包括忙碌标志并查看(文档提到您最好在执行相对 timed_wait 时传递谓词)
  • 如果在您的 while(true) 循环中解锁互斥锁,则可以在线程处于 timed_wait 之前调用 notify_all。

标签: c++ multithreading boost asynchronous


【解决方案1】:

不,您不必重置条件变量,是的,它可以多次工作。

我相信您看到的是死锁,而不是在第二次等待 m_condition 时失败。当您在 stateMachine() 中调用 timed_wait() 时,您的互斥锁将被解锁,并在 timed_wait() 返回时重新锁定。我猜在等待之后的缺失代码中,您正在调用 callbackEvent()。该方法试图锁定互斥体,但它不能,因为 (a) 它已经在调用者 (stateMachine()) 中锁定并且 (b) boost::mutex 不是可重入的。您可以尝试使用例如recursive_mutex 代替。

【讨论】:

  • 我也是这么想的,但是代码(我省略了-> Timeout or Event)不是很多。所以如果我玩这个,它会像这样:1.timed_wait返回(第一次)2.“事件”代码被执行。 3. 下一个命令被调度 4. timed_wait 解锁互斥锁 5. 可以执行回调 此外-我用调试器检查过-我的代码实际上多次执行notify_all
【解决方案2】:

好吧,对我来说不是最光明的时刻,我实际上解决了这个问题。上面发布的代码正在编译并按预期工作。实际问题在于事件或超时的处理。由于那里发生的事情与timed_wait 完全无关,我想我不需要在这里解释。所以这个问题可以结束了。

更新:

当然,由于缺少调度方法,上述代码将无法工作。只是为了它,我要在这里提一下:出于测试目的,我只是在我的主函数中创建一个myClass_A 的对象,启动状态机,然后从我的主函数中调用callbackEvent。这确实有效!

【讨论】:

  • 嗯,上面贴出来的代码不能按预期工作,因为没有dispatch也没有callback,但是你的问题解决了,所以这是最重要的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-03
  • 2018-10-08
相关资源
最近更新 更多