使用 C++17,对于其中包含执行某些任务的非阻塞循环的工作线程,我看到三种方法来通知线程退出:
- 一个
std::atomic_bool
线程在循环中进行检查。如果设置为true
,线程退出。主线程将其设置为true
在调用std::thread::join()
之前. - 一个
std::condition_variable
与bool
。这与上面类似,只是它允许您调用std::condition_variable::wait_for()
在等待潜在的退出信号时有效地“ sleep ”线程(以降低 CPU 使用率)(通过设置bool
,在wait_for()
(谓词)的第三个参数中检查该值。主线程将锁定一个互斥锁,将 bool 值更改为true
,并在调用std::condition_variable::notify_all()
之前调用std::thread::join()
以通知线程退出。 - 一个
std::future
和std::promise
。主线程持有std::promise<void>
而工作线程持有相应的std::future<void>
。工作线程使用std::future::wait_for()
与上面的步骤类似。主线程调用std::promise::set_value()
在调用std::thread::join()
之前.
我对每个问题的想法:
- 这很简单,但缺乏在不显式调用
std::this_thread::sleep_for()
的情况下“减慢”工作线程循环的能力。 。看起来像是一种“老式”的线程信号处理方式。 - 这个很全面,但是非常复杂,因为您需要一个条件变量加上一个 bool 变量。
- 这似乎是最好的选择,因为它具有#1 的简单性,但没有#2 的冗长。但我对
std::future
没有个人经验和std::promise
然而,所以我不确定这是否是理想的解决方案。在我看来,promise 和 future 的目的是跨线程传输值,而不是真正用作信号。所以我不确定是否存在效率问题。
我看到有多种方式来通知线程退出。可悲的是,随着我不断寻找,我的 Google 搜索仅引入了更多内容,而实际上并未就使用 C++17 执行此操作的“现代”和/或“最佳”方法达成普遍共识。
我很想看到一些关于这种困惑的线索。有没有一个决定性的、明确的方法来做到这一点?普遍的共识是什么?如果没有“一刀切”的话,每种解决方案的优缺点是什么?
最佳答案
如果您有一个繁忙的工作线程,需要单向通知(如果它应该停止工作),最好的方法就是使用 atomic<bool>
。如果工作线程想放慢速度或不想放慢速度,则取决于工作线程。 “限制”工作线程的要求与线程取消完全正交,在我看来,不应将其与取消本身一起考虑。据我所知,这种方法有两个缺点:无法传回结果(如果有),并且无法传回异常(如果有)。但如果您不需要其中任何一个,请使用 atomic<bool>
并且不用担心其他任何事情。它和其他任何东西一样现代;没有什么过时的。
condition_variable
是消费者/生产者模式的一部分。因此,有些东西会产生工作,有些东西会消耗所生产的东西。避免忙于等待消费者而没有任何东西可以消费 condition_variable
是一个很好的选择。它是此类任务的完美原语。但对于线程取消过程来说没有意义。无论如何,您都必须使用另一个变量,因为您不能依赖 condition_variable
独自的。它可能会虚假地唤醒线程。您可能会在它进入等待过程之前对其进行“设置”,从而完全丢失“设置”,等等。它不能单独使用,所以我们回到第一个方向,但现在有了 atomic<bool>
变量伴随我们condition_variable
future
/promise
当您需要知道在另一个线程上完成的操作的结果时,pair 是很好的选择。因此,它不能替代 atomic<bool>
的方法。但它是对它的补充。因此,要消除第一段中描述的缺点,您添加 future
/promise
到方程。您向调用方提供 future
摘自promise
它存在于线程内。那promise
线程完成后设置:
- 因为抛出了异常。
- 因为线程已经完成了它的工作并自行完成。
- 因为我们通过设置
atomic<bool>
要求它停止多变的。
如您所见 future
/promise
对只是帮助为被调用者提供一些反馈,它与取消本身无关。
附注您始终可以使用电动大锤来敲碎坚果,但这并不会使该方法变得更加现代。
关于c++ - 如何向 std::thread 发出信号以优雅退出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57728255/