为啥 C++ 标准库中没有线程池?

Posted

技术标签:

【中文标题】为啥 C++ 标准库中没有线程池?【英文标题】:Why is there no thread pool in C++ standard library?为什么 C++ 标准库中没有线程池? 【发布时间】:2021-11-10 10:59:15 【问题描述】:

自 C++11 以来,C++ 中并行/并发编程工具的数量激增:线程、异步函数、并行算法、协程……但是流行的并行编程模式:thread pool?

据我所知,标准库中没有任何东西直接实现这一点。通过std::thread进行线程化可以用来实现线程池,但这需要人工。通过std::async 的异步函数可以在新线程(std::launch::async)或调用线程(std::launch::deferred)中启动。

我认为 std::async 可以很容易地支持线程池:通过另一个启动策略 (std::launch::thread_pool) 在隐式创建的全局线程池中执行任务;或者可能有一个std::thread_pool 对象加上std::async 的重载,它需要一个线程池。

是否考虑过这样的事情,如果考虑过,为什么会被拒绝?或者是否有我缺少的标准解决方案?

【问题讨论】:

你为什么确定std::async使用线程池? 要么是因为1.它没有被提议要么2.这样的提议没有被接受。 我不知道,认为他们想将 stl 限制在更原始的构建块上。不,没有标准的解决方案,但我有一个。 将线程池纳入标准并不容易。我不知道它是如何详细介绍的,但考虑到 C++11 引入了std::thread,而只有 C++20 引入了std::jthread。我想在 C++20 引入 std::jthread 之前需要时间来收集新线程工具的经验,这仍然是低水平的。我希望更高级别的抽象更不容易标准化 有许多不同类型的线程池,为了某些目的选择“最好的”需要非常详细的应用程序知识和(通常)主机系统的属性。这些特征增加了就应该标准化的内容达成一致的难度。对线程池的标准化支持(比如)针对 Windows 进行了良好调整,但针对其他操作系统调整不佳,这与 C++ 的核心理念背道而驰。 【参考方案1】:

原则上std::async 可以使用线程池,在我看来,允许这是意图。但在实践中,thread_local 的存在使其变得困难。

从cppreference 到std::asyncstd::launch::async

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

如果函数包含任何本地thread_local 变量,并且如果std::async 使用线程池,则运行该函数的行为将std::async 可能与std::thread 的行为不同。

一个例子可能是thread_local 在第二次被同一个线程调用时可能没有它的初始值。如果你改用std::thread,它总是有初始值。

行为不同的另一种方式是thread_local 对象的析构函数不会以相同的方式运行std::asyncstd::thread。微软尝试使用线程池就说明了这一点,我怀疑这会吓跑其他人尝试它。您可以在此处阅读有关此不符合项的信息:​​In Visual Studio, thread_local variables' destructor not called when used with std::async, is this a bug?。

为了完全符合要求,无论如何,实现都需要“重置”所有thread_local 对象。这需要编译器支持,并且开始看起来很像开始一个新线程。

【讨论】:

直接链接到 MSVC 的 Stdlib 中的 bug github.com/microsoft/STL/issues/949

以上是关于为啥 C++ 标准库中没有线程池?的主要内容,如果未能解决你的问题,请参考以下文章

为啥C++标准库中没有transform_if?

为啥标准 C++ 库中没有“int pow(int base, int exponent)”?

为啥 Python 的标准库中没有排序容器?

多线程四大经典案例

多线程使用线程池实现一个简单线程池

如何在 C++ 标准库中更改堆中的最大元素?