如何发出std :: thread正常退出的信号?

voi*_*ter 12 c++ multithreading c++17

使用C ++ 17,对于其中执行一些任务的无阻塞循环的工作线程,我看到了三种信号通知线程退出:

  1. std::atomic_bool,在一个循环中的线程检查。如果将其设置为true,则线程退出。主线程true在调用之前将其设置为std::thread::join()
  2. A std::condition_variablebool。这与上面的类似,不同之处在于它允许您std::condition_variable::wait_for()在等待潜在退出信号时调用有效地“休眠”线程(以降低CPU使用率)(通过将bool在第3个参数中检查的设置为wait_for()(谓词) )。主线程将锁定一个互斥锁,将bool更改为true,然后在调用std::condition_variable::notify_all()前调用std::thread::join()以指示该线程退出。
  3. A std::futurestd::promise。主线程持有一个,std::promise<void>而工作线程持有相应的std::future<void>。辅助线程的使用std::future::wait_for()类似于上述步骤。主线程在调用std::promise::set_value()之前先调用std::thread::join()

我的想法:

  1. 这很简单,但是缺乏在不显式调用的情况下“降低”工作线程循环的能力std::this_thread::sleep_for()。好像是执行线程信号的“老式”方法。
  2. 这是全面的,但是非常复杂,因为您需要一个条件变量和一个布尔变量。
  3. 这似乎是最好的选择,因为它具有#1的简单性而没有#2的冗长性。但我有没有亲身经历std::futurestd::promise还,所以我不知道这是否是理想的解决方案。在我看来,promise&future是要在线程之间传递值,而不是真正用作信号。因此,我不确定是否存在效率问题。

我看到了多种信号通知线程退出的方法。令人遗憾的是,我一直在寻找的时候,我的Google搜索只引入了更多内容,而实际上并没有就使用C ++ 17实现这种“现代”和/或“最佳”方式达成普遍共识。

我很想看到这种混乱的曙光。是否有确定的,确定的方式来执行此操作?一般共识是什么?如果没有“一刀切”的解决方案,每种解决方案的利弊是什么?

tte*_*ple 0

我不能说这是结论性的或明确的,但由于这在某种程度上是一个意见问题,我会给出一个答案,它是基于大量的试验和错误来解决您所问的问题(我认为)。

我的首选模式是通知线程停止使用原子布尔,并使用条件变量控制“循环”计时。

我们经常遇到在工作线程上运行重复任务的要求,因此我们创建了一个名为“threaded_worker”的类。此类处理中止线程和计时对工作函数的调用的复杂性。

中止是通过设置原子 bool 'abort' 信号的方法来处理的,该信号告诉线程停止调用工作函数并终止。

循环时间可以通过设置条件变量等待时间的方法来控制。可以通过调用条件变量的通知的方法释放线程以继续。

我们使用该类作为所有类型对象的基类,这些对象具有需要在单独线程上执行的某些功能。该类设计为运行“work”函数一次或循环运行。

我们使用 bool 来中止,因为它简单且适合完成这项工作。我们使用条件变量进行循环计时,因为它的好处是可以通知“短路”计时。当线程对象是消费者时,这非常有用。当生产者有线程对象的工作时,它可以将工作排队并通知工作可用。线程对象立即继续,而不是等待条件变量上指定的等待时间。

两者(中止信号和条件变量)的原因是我将终止线程视为一个函数,并将循环计时视为另一个函数。

我们过去常常通过让线程休眠一段时间来计时循环。这使得在 Windows 计算机上几乎不可能获得可预测的循环时序。有些计算机将在大约 1 毫秒内从睡眠 (1) 返回,但其他计算机将在 15 毫秒内返回。我们的性能高度依赖于特定的硬件。使用条件变量,我们极大地改善了关键任务的时间安排。当工作可用时通知等待线程的额外好处是值得条件变量的复杂性的。