我使用 boost::thread 来管理线程。在我的程序中,我有一些线程(工作线程)池,它们有时会被激活以同时完成某些工作。
现在我使用 boost::condition_variable: 并且所有线程都在 boost::condition_variable::wait() 内部等待调用它们自己的 conditional_variableS 对象。
当我使用 conditional_variables 时,我可以避免在经典方案中使用互斥量吗?我想唤醒线程,但不需要向它们传递一些数据,所以在唤醒过程中不需要锁定/解锁互斥锁,我为什么要在这上面花费 CPU(但是是的,我应该记得虚假唤醒)?
当 CV 收到通知时,boost::condition_variable::wait() 调用试图重新获取锁定对象。但我不需要这个确切的设施。
从另一个线程唤醒多个线程的成本最低的方法是什么?
最佳答案
如果不重新获取锁定对象,线程如何知道它们已经等待完毕?什么会告诉他们?从阻塞返回不会告诉他们任何事情,因为阻塞对象是无状态的。它没有用于返回的“解锁”或“未阻止”状态。
您必须向他们传递一些数据,否则他们怎么知道之前他们必须等待而现在他们不必等待?条件变量是完全无状态的,因此您必须维护和传递您需要的任何状态。
一种常见的模式是使用互斥量、条件变量和状态整数。要阻止,请执行以下操作:
获取互斥锁。
复制状态整数的值。
阻塞条件变量,释放互斥量。
如果状态整数与您处理时的状态整数相同,则转到步骤 3。
释放互斥体。
要取消阻塞所有线程,请执行以下操作:
获取互斥锁。
增加状态整数。
广播条件变量。
释放互斥体。
请注意锁定算法的第 4 步如何测试线程是否已完成等待?请注意此代码如何跟踪自线程决定阻塞以来是否存在解除阻塞?您必须这样做,因为条件变量本身不会这样做。 (这就是您需要重新获取锁定对象的原因。)
如果您尝试删除状态整数,您的代码将出现不可预测的行为。有时你会因为错过唤醒而阻塞太久,有时你不会因为虚假唤醒而阻塞足够长的时间。只有受互斥锁保护的状态整数(或类似谓词)告诉线程何时等待以及何时停止等待。
此外,我还没有看到您的代码如何使用它,但它几乎总是融入您已经在使用的逻辑中。为什么线程仍然阻塞?是因为他们没有工作可做吗?当他们醒来时,他们会想办法做什么吗?好吧,发现他们没有工作可做,并找出他们需要做的工作将需要一些锁,因为它是共享状态,对吗?因此,当您决定阻止时,几乎总是已经持有一把锁,并且在等待完成后需要重新获取。
关于c++ - 在不阻塞的情况下唤醒多个等待线程的最便宜方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9789488/