如何阻止直到满足条件

时间:2016-03-16 01:41:48

标签: c++ c++11

我想知道在条件成立之前阻止方法的最佳方法是什么。

示例:

class DoWork
{
  int projects_completed;
  public:
  .....
  void WaitForProjectsCompleted()
  {
   ---->//How do I block until projects_completed == 12;
  }
};

我希望它可以这样使用

class foo
{
 ....
 void someMethod()
 {
    DoWork work;
    work.WaitForProjectsCompleted();//This should block
 }
}

2 个答案:

答案 0 :(得分:2)

假设有另一个线程实际上要在这里做一些事情,一个简单易用的东西是std::condition_variable

std::condition_variable cv;
std::mutex mtx;

void WaitForProjectsCompleted() {
    std::unique_lock<std::mutex> lk(mtx);
    cv.wait(mtx, [this]{ return projects_completed >= 12; });
}

在其他地方,某些其他成员函数可能会这样做:

void CompleteProject() {
    {
        std::lock_guard<std::mutex> lk(mtx);
        ++projects_completed;
    }
    cv.notify_one(); // let the waiter know
}

如果projects_completed是原子的,你可以改为旋转:

void WaitForProjectsCompleted() {
    while (projects_completed < 12) ;
}

那也行得很好。

答案 1 :(得分:1)

条件变量是一个很好的同步原语,根据我的个人经验,它是我回应95%同步/线程情况的工具。

如果您没有C ++ 11可用,则可以使用boost::condition_variable 在这种情况下,您不会拥有带谓词的wait版本(因为C ++ 03中没有lambdas)。所以你绝对需要记住循环你的状况检查。正如文档中所解释的那样:

boost::unique_lock<boost::mutex> lock(mut);
while (projects_completed < 12)
{
    wait(lock);
}

c.f .:
http://www.boost.org/doc/libs/1_58_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref

这是因为您无法保证在通知后满足条件,特别是因为锁定可以由解锁和通知之间的空隙中的另一个线程获取。也可能发生虚假的唤醒。

我还写了一篇关于它的文章:
http://www.gamedev.net/page/resources/_/technical/general-programming/multithreading-r3048

此外,如果你使用timed_wait(我推荐它,因为它经常减轻priority inversion),另一个不陷入的陷阱是超时,因为循环你不能使用相对超时(如2秒)您需要在进入循环之前确定绝对系统时间 boost使用这种技术使其非常干净:

system_time const timeout = get_system_time() + posix_time::seconds(2);

关于Barry提出的旋转锁定模式,我不推荐它,除非你是在实时环境中,比如playstation 3/4或同等版本。或者,除非你确定它不会持续超过几秒钟 通过使用旋转锁定可以浪费电力,并且不会让CPU有机会进入睡眠状态(参见英特尔速度步骤)。
这也会对公平性和日程安排产生影响,如维基百科所述: https://en.wikipedia.org/wiki/Spinlock

最后,如果你没有提升,那么从Windows Vista开始我们就可以获得原生的Win32功能了:
SleepConditionVariableCS
https://msdn.microsoft.com/en-us/library/windows/desktop/ms686301(v=vs.85).aspx