可以长时间运行std :: asyncs饿死其他std :: asyncs吗?

时间:2017-11-30 12:31:28

标签: c++ multithreading c++11 asynchronous stdasync

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

所以我要说我首先创建并安排足够长时间运行的std::async来保持该线程池中的所有线程都被占用。之后(不久他们就完成了执行)我还创建并安排了一些短期运行的std::async。可能会发生这样一个短期运行的问题,直到至少有一个长期运行的问题完成之后才会执行?或者标准(特别是C ++ 11)中是否有一些保证可以防止出现这种情况(例如产生更多线程以便操作系统可以在循环方式中安排它们)?

2 个答案:

答案 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::asyncstd::thread的原始调用更实用,并且因为用{编写一个线程池真的很容易{1}}或std::thread,我建议用std::async编写一个。

您的线程池可以像std::thread那样返回std::future(但没有自动阻塞的销毁功能,因为池本身可以管理线程生存期)。

我已经读过C ++ 17增加了更好的前进进度保证,但是我缺乏足够的理解来判断MSVC的行为是否符合标准要求。