32

关于Herb Sutter 演讲then()中函数的实现,我有几个问题。此函数用于链接异步操作,参数是一个操作的未来,参数是此操作的“工作”(lambda)。fw

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

应用示例如下:

    std::future<int> f = std::async([]{
        std::this_thread::sleep_for(std::chrono::microseconds(200));
        return 10;
    });

    auto f2 = then(std::move(f), [](int i){
        return 2 * i;
    });

主线程产生任务,但不等待其中任何一个完成。

首先,future<T>没有复制构造函数。shared_future<T>这意味着,除非我们将调用更改async()为将未来移动到 lambda 中,否则建议的实现只能与一起使用。这个 SO question提出了一种方法,但它似乎太复杂了。我重新实现了这个功能,我想知道我的代码是否正确或者我是否遗漏了什么......

其次,传递给then()函数的未来可能是void所以我们实际上需要 2 个实现then(),对吧?一种用于期货退货T,一种用于期货退货void

最后,内部的 lambda 是否应该then()没有 return 语句,以便我们可以实际返回值?没有 return 语句,然后返回future<void>,对吗?

我试图解决以上几点,这就是我想出的。这是对的吗?

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

template <typename Work>
auto then(future<void> f, Work w) -> future<decltype(w())>
{
    return async([](future<void> f, Work w)
                      { f.wait(); return w(); }, move(f), move(w));
}
4

3 回答 3

5

这种 .then() 方法的问题在于您同时生成 2 个线程(这是昂贵的),其中第二个线程会阻塞它的 future.get/wait (当然,如果第一个线程运行时间足够长)所以,最好使用工作队列,序列化作业执行顺序(并重新循环现有线程)。只需寻找一个好的线程池模式实现

于 2017-08-15T11:20:53.397 回答
4

为了简化界面,我会void在实现中“隐藏”问题,类似于 Herb 对他的concurrent<T>实现所做的。不要有 2 个then实现,而是声明一个具有 2 个实现的辅助函数get_work_done

template <typename T, typename Work>
auto get_work_done(future<T> &f, Work &w)-> decltype(w(f.get()))
{return w(f.get());}

template <typename Work>
auto get_work_done(future<void> &f, Work &w)-> decltype(w())
{f.wait(); return w();}

然后让模板参数检测处理剩下的事情:

template <typename T, typename Work>
auto then(future<T> f, Work w) -> future<decltype(w(f.get()))>
{
    return async([](future<T> f, Work w)
                      { return get_work_done(f,w); }, move(f), move(w));
}
于 2013-02-18T11:54:35.560 回答
1

不,这是不正确的。如果将 .get() 的返回值传递给 continuation,它将无法处理从 .get() 传播的异常。您必须将 future 传递给 continuation,并手动调用 .get() ,就像在 boost.thread 中一样

于 2013-02-20T00:23:13.370 回答