long-运行 std::asyncs 能饿死其他 std::asyncs 吗?

Can long-running std::asyncs starve other std::asyncs?

据我了解,std::async 的通常实现会在来自预分配线程池的线程上安排这些作业。

所以假设我首先创建并安排了足够长的 运行 std::asyncs 来保持该线程池中的所有线程被占用。紧接着(在他们完成执行之前不久)我还创建并安排了一些 short-运行 std::asyncs。短 运行 至少有一个长 运行 完成后才执行吗?或者在标准(特别是 C++11)中是否有一些保证可以防止这种情况(比如生成更多线程以便 OS 可以在循环法中调度它们)?

标准为:

[futures.async#3.1] If launch​::​async is set in policy, calls INVOKE(DECAY_­COPY(std​::​forward<F>(f)), DECAY_­COPY(std​::​forward<Args>(args))...) ([func.require], [thread.thread.constr]) as if in a new thread of execution represented by a thread object with the calls to DECAY_­COPY being evaluated in the thread that called async.[...]

因此,根据 as-if 规则,new 线程必须在 async() 被调用时生成 ​async 启动策略。当然,一个实现可能会在内部使用线程池,但是除了通常的线程创建开销之外,不会发生特殊的 'starving' 。此外,线程局部变量的初始化之类的事情应该总是发生。

事实上,clang libc++ 主干异步实现如下:

unique_ptr<__async_assoc_state<_Rp, _Fp>, __release_shared_count>
        __h(new __async_assoc_state<_Rp, _Fp>(_VSTD::forward<_Fp>(__f)));

VSTD::thread(&__async_assoc_state<_Rp, _Fp>::__execute, __h.get()).detach();

return future<_Rp>(__h.get());

如您所见,内部没有使用'explicit'线程池。

此外,如您所见,here gcc 5.4.0 附带的 libstdc++ 实现仅调用普通线程。

是的,MSVC 的 std::async 似乎完全符合 属性,至少从 MSVC2015 开始是这样。

我不知道他们是否在 2017 年更新中修复了它。

这违背了标准的精神。但是,该标准对线程转发进度保证非常模糊(至少从 C++14 开始)。因此,虽然 std::async 必须表现得好像它包裹了 std::thread,但对 std::thread 前进进度的保证非常薄弱,以至于在假设规则下这并不是一个很大的保证。

实际上,这导致我用对 std::thread 的原始调用替换线程池实现中的 std::async,因为在 MSVC2015 中 std::thread 的原始使用似乎没有有这个问题。

我发现线程池(带有任务队列)比对 std::asyncstd::thread 的原始调用实用得多,而且编写线程池真的很容易std::threadstd::async,我建议写一个 std::thread

您的线程池可以 return std::future 就像 std::async 一样(但没有销毁时自动阻塞功能,因为池本身管理线程生命周期)。

我读到 C++17 添加了更好的前进进度保证,但我缺乏足够的理解来断定 MSVC 的行为现在是否违反标准要求。