c++11异步延续或尝试.then()语义

c++11 async continuations or attempt at .then() semantics

本文关键字:then 语义 异步 延续 c++11      更新时间:2023-10-16

下面的代码是基于Herb Sutter关于.then()类型延续的实现思想。

  template<typename Fut, typename Work>
auto then(Fut f, Work w)->std::future<decltype(w(f.get()))>
  { return std::async([=] { w(f.get()); }); }

这将用于auto next = then(f, [](int r) { go_and_use(r); });或类似的。

这是一个巧妙的想法,但就目前来看是行不通的(期货是移动的,不可复制的)。我确实喜欢这个想法,因为据我猜测,它很可能出现在即将到来的c++版本中(尽管是.then()甚至await.)

在让未来共享或类似之前,我想知道堆栈溢出社区会如何看待这个实现,特别是改进和建议(甚至共享未来)?

提前感谢您的建议。

(我知道这是一个修复,直到一个基于标准的机制存在,因为它将花费一个线程(可能)))。

我发现上述实现有3个问题:

  • 只有当你将std::shared_future作为Fut传递时才会起作用。
  • 延续可能需要处理异常的机会。
  • 它并不总是按照预期的方式运行,因为如果您没有指定std::launch::async,它可能会被延迟,因此不会像预期的那样调用延续。

我试着解决这些问题:

template<typename F, typename W, typename R>
struct helper
{
    F f;
    W w;
    helper(F f, W w)
        : f(std::move(f))
        , w(std::move(w))
    {
    }
    helper(const helper& other)
        : f(other.f)
        , w(other.w)
    {
    }
    helper(helper&& other)
        : f(std::move(other.f))
        , w(std::move(other.w))
    {
    }
    helper& operator=(helper other)
    {
        f = std::move(other.f);
        w = std::move(other.w);
        return *this;
    }
    R operator()()
    {
        f.wait();
        return w(std::move(f)); 
    }
};
}
template<typename F, typename W>
auto then(F f, W w) -> std::future<decltype(w(F))>
{ 
    return std::async(std::launch::async, detail::helper<F, W, decltype(w(f))>(std::move(f), std::move(w))); 
}

像这样使用:

std::future<int> f = foo();
auto f2 = then(std::move(f), [](std::future<int> f)
{
    return f.get() * 2; 
});

下面是用g++ 4.8和clang++ 3.2测试的解决方案:

template<typename F, typename W>
auto then(F&& f, W w) -> std::future<decltype(w(f.get()))>
{
  cout<<"In thread id = "<<std::this_thread::get_id()<<endl;
  return std::async(std::launch::async, w, f.get());
}
void test_then()
{
  std::future<int> result=std::async([]{ return 12;});
  auto f = then(std::move(result), [](int r) {
    cout<<"[after] thread id = "<<std::this_thread::get_id()<<endl;
    cout<<"r = "<<r<<endl;
    return r*r;
  });
  cout<<"Final result f = "<<f.get()<<endl;
}