C++标准库为什么没有线程池?

4
自从C++11以来,C++中的并行/并发编程工具数量激增:线程、异步函数、并行算法、协程...但是关于一种流行的并行编程模式线程池呢?
就我所知,标准库中没有直接实现此功能。可以使用std::thread执行线程池,但这需要手动完成。可以通过std::async异步函数在新线程(std::launch::async)或调用线程(std::launch::deferred)中启动。
我认为可以很容易地使std::async支持线程池:通过另一个启动策略(std::launch::thread_pool),在隐式创建的全局线程池中执行任务;或者有一个std::thread_pool对象加上对std::async的重载函数,它接受一个线程池。
是否考虑过类似于此的解决方案,如果是,为什么被拒绝了?或者是否有我错过的标准解决方案?

3
可能是因为 1. 还没有被提出,或者 2. 提议尚未被接受。 - eerorika
@Useless 这是实现特定的。只有在使用 MSVC 的 Windows 上才会使用线程池,其他实现不使用线程池。 - Pepijn Kramer
2
将线程池引入标准并不容易。我不知道它是如何被引入的,但需要考虑到C++11引入了std::thread,而只有C++20引入了std::jthread。我认为在引入std::jthread之前需要积累使用新线程设施的经验,而这仍然是低级别的。我预计更高级别的抽象甚至更难标准化。 - 463035818_is_not_a_number
2
有许多不同类型的线程池,选择某个目的的“最佳”需要对应用程序和主机系统的属性有相当详细的了解。这些特性增加了达成标准化协议的难度。将支持针对Windows进行良好调整但对其他操作系统调整不足的线程池标准化,与C++的核心理念相悖。 - Peter
1
@Useless,使用线程池是无效的,因为std::future需要一个线程。事实上,MSVC不得不修补他们的std::async,以便出于这个原因使用线程池。具体来说,http://eel.is/c++draft/futures#state-10和相关部分会引起严重的头痛。 - Mgetz
显示剩余3条评论
1个回答

6
原则上,std::async 可以使用线程池,并且我认为允许这样做是有意图的。但实际上,thread_local 的存在使得这很困难。
cppreference 上关于 std::launch::asyncstd::async 中:

[...] 在新的执行线程上执行可调用对象f(初始化所有线程本地变量),就像由std::thread(std::forward<F>(f), std::forward<Args>(args)...)生成的一样 [...]

如果函数包含任何局部的 thread_local 变量,并且 std::async 使用了线程池,运行函数的行为将与使用 std::thread 的行为不同。
一个例子可能是 thread_local 第二次被同一线程调用时可能没有初始值。如果你使用 std::thread 代替,它将始终具有初始值。
另一种行为分歧的方式是,thread_local对象的析构函数在std::async和std::thread中不会以相同的方式运行。这可以通过Microsoft尝试使用线程池来说明,我怀疑这也吓退了其他人。您可以在此处阅读有关此非一致性的信息:在Visual Studio中,thread_local变量与std::async一起使用时析构函数无法调用,这是一个错误吗?
要完全符合,实现将需要“重置”所有thread_local对象。这需要编译器支持,并开始看起来非常像启动一个新线程。

MSVC标准库中的错误直接链接https://github.com/microsoft/STL/issues/949 - Mgetz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接