简体   繁体   中英

Why does boost::when_all spawn a new thread

I have the following code, compiled with Boost 1.62.

#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_PROVIDES_EXECUTORS

#include <chrono>
#include <thread>
#include <boost/thread/future.hpp>
#include <boost/thread/executors/loop_executor.hpp>

using namespace std::literals::chrono_literals;
int main() {

    auto start = boost::make_ready_future<int>();

    boost::loop_executor ex;

    auto a = start.then(ex, [](auto &&) { std::cout << "A"; }).share();

    auto b = boost::when_all(a).then(ex, [](auto &&) { std::cout << "B";} );
    auto c = boost::when_all(a).then(ex, [](auto &&) { std::cout << "C";} );

    auto d = boost::when_all(std::move(b),std::move(c)).then(ex, [](auto &&) { std::cout << "D";} );

    while ( ex.try_executing_one() )
         std::this_thread::sleep_for(100ms);

    d.get();

    return 0;
}

This spawns 4 tasks (A,B,C,D) with a diamond dependency over them ( B and C depend on A, D depends on B and C ).

Given the fact that I am using a loop_executor , I expected this code to not spawn any thread and output either "ABCD" or "ACBD".

Instead this code might or might not deadlock at d.get() (just reduce the sleep time to zero to see it deadlocking), because every call to when_all spawns a new thread that is used to wait on the futures .

I was under the impression that when_all could simply be implemented in terms of .then , some buffer to store the task result and an atomic counter.

Question:

Is there a fundamental design reason that requires when_all to spawn a new thread?

In particular I am wondering if this behavior is to be expected also from an hypothetical implementation of the concurrency TS.

In my opinion, boost::when_all is not spawn a new thread, I think this logic is simple follow the semantic can help you understand. boost::loop_executor spawns threads, and boost::when_all give the threads a order. loop_executor mean execute in loop, so if d.get() happened, it will deadlock.

I know what you mean now, if you change std::this_thread::sleep_for(2us) ; you will find it works somtimes while getting deadlock somtimes. The deadlock is not really deadlock, result of while (ex.try_executing_one()) loop is out. ex.try_executing_one() should wait boost::when_all(a) is finish because the order you set, and future is asynchronous.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM