我实现了一个简单的ThreadPool,它使用std::list<Tasks> mTasks
作为任务列表。
所有线程都使用以下代码等待条件变量:
EnterCriticalSection(&mCriticalSection);
while(mTasks.size() ==0)
SleepConditionVariableCS(&mConditionVariable,&mCriticalSection, INFINITE);
直到有人在名单上添加了什么,然后其中一个被唤醒。
我使用了一段时间来检查任务列表是否为空,尽管唤醒任务列表的唯一方法是向列表中添加一个新任务(所以它不能是空的),我之所以这样做是因为在MSDN中它是编写的:
条件变量受虚假唤醒(与显式唤醒无关的唤醒)和被窃唤醒(另一个线程设法在唤醒线程之前运行)的影响。因此,您应该在睡眠操作返回后重新检查谓词(通常在while循环中)。
但是那些虚假的唤醒是什么,什么会唤醒我的变量?
发布于 2014-01-28 17:07:32
当我在大学学习的时候,我对这个话题的理解是,从性能的角度来说,实现100%的安全条件变量会花费太大。
维基百科关于假唤醒的页面引用了大卫·R·布滕霍夫(Programming with POSIX Threads
的作者)的话:
这意味着当您在条件变量上等待时,当没有线程具体地广播或发出该条件变量的信号时,等待可能(偶尔)返回。虚假的唤醒可能听起来很奇怪,但在一些多处理器系统上,使条件唤醒完全可预测可能会大大减缓所有条件变量操作。引起虚假唤醒的种族条件应该被认为是罕见的。
在while
循环中检查一个条件是一个很好的实践,肯定会避免这个问题。
对于更多关于为什么会发生这种事情的关注,我很抱歉,但我不能提供这样的见解。
发布于 2014-01-28 17:13:53
我认为问题在于多处理器系统中多个处理器之间的同步.
为了尽可能地保持条件变量的轻量级,实现使用某些线程原语,虽然线程是安全的,但是当实际只发出一个调用时,条件变量会注册两个notify()
风格的调用。这是一种罕见的场景,而且设计人员通过处理这个场景降低了效率,从而将问题推到用户代码中,在用户代码中,如果可能影响到您,您只需担心它。
https://stackoverflow.com/questions/21411912
复制相似问题