我想知道在条件成立之前阻止方法的最佳方法是什么。
示例:
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
}
}
答案 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);
}
这是因为您无法保证在通知后满足条件,特别是因为锁定可以由解锁和通知之间的空隙中的另一个线程获取。也可能发生虚假的唤醒。
我还写了一篇关于它的文章:
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