使用C ++ notify_all()

时间:2015-10-25 21:16:15

标签: c++ multithreading c++11 design-patterns

我的障碍同步方案是:

一个。线程在同步中向前迈出一步 - 即它们完成一个任务单元然后等待所有其他线程执行相同的操作,然后当它们执行时,它们可以再次向前移动。

湾我有大量的线程(大约256个)在条件变量上等待。满足条件时,将发送notify_all()

℃。 (出现饥饿风险的部分):在调用notify_all()之前,runnable变量设置为true,计数器 - completed - 设置为零。当线程完成其任务单元时,它会调用一个函数,该函数首先将runnable设置为false,然后递增completed变量 - 当completed等于阈值时满足条件(即需要完成任务单元的线程数),其中runnable设置为true。

即,我们这样等待:

cond.wait(lck, runnable == true);

并且有这个:

unique_lock<mutex> lck(runMut);
runnable = true;
cond.notify_all();

我担心的是,任何一个醒来的线程都可以完成它的任务,然后在链中的一个线程被唤醒之前调用wait()函数。当这个“低级”线程测试runnable时,它会发现它设置为false,然后再回到睡眠状态。

是否有设计模式或其他方式可以解决这个问题?

3 个答案:

答案 0 :(得分:2)

您可以使用两个条件变量。一个通知工人开始工作,一个通知工人已完成工作。即你的主线程看起来像这样:

for (;;) {
  running = 0;
  done = 0;
  cond_run.notify_all();
  cond_done.wait(lck, []() { return done == threads; });
  // handle results
}

你的工作线程看起来像这样:

for (;;) {
  cond_run.wait(lck, []() { return running < threads; });
  ++running;
  lck.unlock();
  // do work
  lck.lock():
  ++done;
  cond_done.notify_one();
}

答案 1 :(得分:0)

并发很难。有很多方法可以解决这个问题,但真正重要的是让自己很容易确保它做对了。在这种特殊情况下,使用布尔值“runnable”来指示线程何时可以开始运行是令人困惑的。

相反,我会使用int currentStage指示每个人应该执行的阶段,并使用int numComplete来指示已完成currentStage的线程数。确保只在锁定状态下访问状态并且只进行有效转换 - 将numComplete增加到256的线程也应该将其重置为0并在释放锁定之前增加currentStage。

确保在对该状态进行任何更改后触发notify_all,然后很容易确保每个线程都做正确的事情。

答案 2 :(得分:0)

我实际上找不到一种让它工作的方法 - 问题是上面建议的两个变量解决方案没有处理虚假的唤醒,所以我选择通过不打扰谓词和生活来简化这个有关虚假唤醒的问题。