据我了解,std :: async的常规实现在预先分配的线程池的线程上安排这些作业。
所以我要说我首先创建并安排足够长时间运行的std::async
来保持该线程池中的所有线程都被占用。之后(不久他们就完成了执行)我还创建并安排了一些短期运行的std::async
。可能会发生这样一个短期运行的问题,直到至少有一个长期运行的问题完成之后才会执行?或者标准(特别是C ++ 11)中是否有一些保证可以防止出现这种情况(例如产生更多线程以便操作系统可以在循环方式中安排它们)?
答案 0 :(得分:2)
标准如下:
[futures.async#3.1]如果在策略中设置了launch :: async,则调用
INVOKE(DECAY_COPY(std::forward<F>(f)), DECAY_COPY(std::forward<Args>(args))...)
([func.require],[thread.thread.constr]),就好像在由线程对象表示的新执行线程,在调用异步的线程中对DECAY_COPY的调用进行评估。 [...]
因此,在 as-if 规则下,当使用async()
启动策略调用async
时,必须生成新线程。当然,实现可以在内部使用线程池,但是,除了通常的线程创建开销之外,不会发生特殊的“饥饿”。此外,应始终发生线程本地的初始化等事情。
实际上,clang libc ++ trunk异步实现读取:
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());
如您所见,内部没有使用“显式”线程池。
此外,正如您可以阅读here一样,使用gcc 5.4.0发布的libstdc ++实现只是调用一个普通的线程。
答案 1 :(得分:0)
是的,MSVC的std::async
似乎具有该属性,至少从MSVC2015开始。
我不知道他们是否在2017年更新中修复了它。
这违背了标准的精神。但是,标准对于线程转发进度保证非常模糊(至少从C ++ 14开始)。因此,虽然std::async
的行为必须像包裹std::thread
一样,但std::thread
前进进度的保证足够弱,以至于这不是as-if规则下的保证。< / p>
实际上,这导致我使用std::async
的原始调用替换我的线程池实现中的std::thread
,因为MSVC2015中std::thread
的原始使用似乎没有问题
我发现一个线程池(带有一个任务队列)比对std::async
或std::thread
的原始调用更实用,并且因为用{编写一个线程池真的很容易{1}}或std::thread
,我建议用std::async
编写一个。
您的线程池可以像std::thread
那样返回std::future
(但没有自动阻塞的销毁功能,因为池本身可以管理线程生存期)。
我已经读过C ++ 17增加了更好的前进进度保证,但是我缺乏足够的理解来判断MSVC的行为是否符合标准要求。