c++ - 在不阻塞的情况下唤醒多个等待线程的最便宜方法

标签 c++ multithreading boost synchronization

我使用 boost::thread 来管理线程。在我的程序中,我有一些线程(工作线程)池,它们有时会被激活以同时完成某些工作。

现在我使用 boost::condition_variable: 并且所有线程都在 boost::condition_variable::wait() 内部等待调用它们自己的 conditional_variableS 对象。

当我使用 conditional_variables 时,我可以避免在经典方案中使用互斥量吗?我想唤醒线程,但不需要向它们传递一些数据,所以在唤醒过程中不需要锁定/解锁互斥锁,我为什么要在这上面花费 CPU(但是是的,我应该记得虚假唤醒)?

当 CV 收到通知时,boost::condition_variable::wait() 调用试图重新获取锁定对象。但我不需要这个确切的设施。

从另一个线程唤醒多个线程的成本最低的方法是什么?

最佳答案

如果不重新获取锁定对象,线程如何知道它们已经等待完毕?什么会告诉他们?从阻塞返回不会告诉他们任何事情,因为阻塞对象是无状态的。它没有用于返回的“解锁”或“未阻止”状态。

您必须向他们传递一些数据,否则他们怎么知道之前他们必须等待而现在他们不必等待?条件变量是完全无状态的,因此您必须维护和传递您需要的任何状态。

一种常见的模式是使用互斥量、条件变量和状态整数。要阻止,请执行以下操作:

  1. 获取互斥锁。

  2. 复制状态整数的值。

  3. 阻塞条件变量,释放互斥量。

  4. 如果状态整数与您处理时的状态整数相同,则转到步骤 3。

  5. 释放互斥体。

要取消阻塞所有线程,请执行以下操作:

  1. 获取互斥锁。

  2. 增加状态整数。

  3. 广播条件变量。

  4. 释放互斥体。

请注意锁定算法的第 4 步如何测试线程是否已完成等待?请注意此代码如何跟踪自线程决定阻塞以来是否存在解除阻塞?您必须这样做,因为条件变量本身不会这样做。 (这就是您需要重新获取锁定对象的原因。)

如果您尝试删除状态整数,您的代码将出现不可预测的行为。有时你会因为错过唤醒而阻塞太久,有时你不会因为虚假唤醒而阻塞足够长的时间。只有受互斥锁保护的状态整数(或类似谓词)告诉线程何时等待以及何时停止等待。

此外,我还没有看到您的代码如何使用它,但它几乎总是融入您已经在使用的逻辑中。为什么线程仍然阻塞?是因为他们没有工作可做吗?当他们醒来时,他们会想办法做什么吗?好吧,发现他们没有工作可做,并找出他们需要做的工作将需要一些锁,因为它是共享状态,对吗?因此,当您决定阻止时,几乎总是已经持有一把锁,并且在等待完成后需要重新获取。

关于c++ - 在不阻塞的情况下唤醒多个等待线程的最便宜方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9789488/

相关文章:

c++ - 开始和结束数组索引算法

java - JVM 是否有最坏的情况实现?

boost::numeric::odeint 对于刚性系统,如果我们无法获得解析雅可比矩阵怎么办?

c++ - 从状态内的自定义函数(不是 Action ) boost MSM 调用 process_event?

c++ - 如何使用 boost lambda 在集合中的每个元素上调用方法?

java - 一般套接字问题 - 将 C++ 结构从 Java 转移到 C++

c++ - CUDA Nsight - 将有关内核执行的信息保存到 excel 文件

c++ - 当我可以使用换行符时,为什么要使用 endl?

winforms - 从后台线程更新 UI,当线程完成时,该线程在主 UI 中循环调用

multithreading - 黑莓线程卡在SQLite语句上准备