为什么boost :: when_all会产生一个新线程

时间:2016-11-10 09:46:10

标签: c++ boost future boost-thread

我有以下代码,使用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;
}

这产生4个任务(A,B,C,D),它们具有钻石依赖性(B和C取决于A,D取决于B和C)。

鉴于我使用的是loop_executor,我希望这段代码不会产生任何线程并输出&#34; ABCD&#34;或者&#34; ACBD&#34;。

相反,此代码可能会或可能不会在d.get()处死锁(只需将睡眠时间减少到零以查看死锁),因为每次调用when_all都会产生一个用于等待的新线程futures

我的印象是when_all可以简单地用.then实现,一些缓冲区用于存储任务结果和原子计数器。

问题:

是否存在需要when_all生成新线程的基本设计原因?

特别是我想知道是否也会从并发TS的假设实现中预期到这种行为。

2 个答案:

答案 0 :(得分:-1)

在我看来,boost::when_all不会产生一个新的线程,我认为这个逻辑很简单,遵循语义可以帮助你理解。 boost::loop_executor生成线程,boost::when_all为线程提供订单。 loop_executor表示在循环中执行,因此如果d.get()发生,它将会死锁。

答案 1 :(得分:-1)

我知道你现在的意思,如果你改变 std :: this_thread :: sleep_for(2us);你会发现它很快就能解决死锁问题。死锁不是真正的死锁,是 while(ex.try_executing_one())循环结果的结果。 ex.try_executing_one()应该等待 boost :: when_all(a)完成,因为您设置的顺序和将来是异步的。