我对延续的期货的调度和生命周期有疑问。
如果您将来在
boost::future
上创建延续,然后函数返回而不阻塞延续本身的结果,它将运行延续。
如下所示:
#include <iostream>
#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
#include <boost/thread/future.hpp>
auto calculate_foo(int input) {
auto a = boost::async([input]{
std::cout << input << std::endl;
return input * 2;
});
auto s = a.share();
auto b = s.then([](auto t) {
auto v = t.get();
std::cout << v << std::endl;
boost::this_thread::sleep_for(boost::chrono::milliseconds(v));
});
auto c = s.then([](auto t) {
auto v = t.get();
std::cout << v << std::endl;
boost::this_thread::sleep_for(boost::chrono::milliseconds(v));
});
return s;
}
int main() {
auto z = calculate_foo(1000);
z.wait();
return 0;
}
所以我有一个函数
calculate_foo
可以开始一些工作。然后我们创建 2 个延续 b
和 c
并故意在其中等待 sleep 以确保 calculate_foo
快速返回。
我原以为
b
和 c
仍然会被安排,因为我们返回了 parent future 但这似乎没有发生。
欢迎任何帮助来纠正我的理解。
在您的代码中,您永远不会请求
b
和 c
期货的结果,因此,由于默认的 执行策略 此代码永远不会执行。
传递给
async()
的代码根据其参数指定的执行策略执行。对于launch::async
策略,它在不同的线程中执行,而对于launch::deferred
,它将在您请求未来的结果(或调用wait()
)时内联执行。这同样适用于传递给 then()
的代码,因为它在内部只调用 async()
.
默认的执行策略是
launch::async | launch::deferred
,它让库决定使用哪个策略,通常选择延迟选项。因此,由于从未请求过结果,因此根本没有执行代码。
boost
vs std
的注意事项:请记住,
then()
函数是实验性的,不符合 C++ 标准std::future
。自从 C++11 发布以来,您应该更喜欢使用标准库设施而不是boost
。在特性被纳入标准之前,Boost 通常充当“游乐场”。您可以使用 then()
实现 std::future
之类的功能,如下所示:
template<typename T, typename Func>
auto chain_to(std::launch policy, std::shared_future<T> f, Func&& second_func) {
return std::async(policy, [f, second_func = std::forward<Func>(second_func)]() {
return second_func(f);
});
}
template<typename T, typename Func>
auto chain_to(std::shared_future<T> f, Func&& second_func) {
return std::async([f, second_func = std::forward<Func>(second_func)]() {
return second_func(f);
});
}
// Use like:
auto b = chain_to(std::launch::async, my_first_shared_future, [](auto f) { ... });
这个 Godbolt 演示了使用
launch::async
你的代码将导致所有三个 lambda 被调用。