Search code examples
c++multithreadingc++11asynchronousstdasync

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


As I understand it, usual implementations of std::async schedule these jobs on threads from a pre-allocated thread pool.

So lets say I first create and schedule enough long-running std::asyncs to keep all threads from that thread pool occupied. Directly afterwards (before long they finished executing) I also create and schedule some short-running std::asyncs. Could it happen that the short-running ones aren't executed at all until at least one of the long-running ones has finished? Or is there some guarantee in the standard (specifically C++11) that prevents this kind of situation (like spawning more threads so that the OS can schedule them in a round-robin fasion)?


Solution

  • The standard reads:

    [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.[...]

    so, under the as-if rule, new threads must be spawned when async() is invoked with ​async launch policy. Of course, an implementation may use a thread pool internally but, usual thread creation overhead aside, no special 'starving' can occur. Moreover, things like the initialization of thread locals should always happen.

    In fact, clang libc++ trunk async implementation reads:

    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());
    

    as you can see, no 'explicit' thread pool is used internally.

    Moreover, as you can read here also the libstdc++ implementation shipping with gcc 5.4.0 just invokes a plain thread.