我有以下代码,使用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的假设实现中预期到这种行为。
答案 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)完成,因为您设置的顺序和将来是异步的。