web-dev-qa-db-ja.com

c ++ 11での非同期実行と同等のfuture :: then()の実装

ハーブサッターの話 の関数then()の実装についていくつか質問があります。この関数は非同期操作を連鎖させるために使用され、パラメーターfは1つの操作からの未来であり、パラメーターwはこの操作(ラムダ)の「作業」です。

_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>_にはコピーコンストラクターがありません。つまり、提案された実装は、async()の呼び出しを変更して未来をラムダに移動しない限り、_shared_future<T>_でのみ使用できます。 これSO質問 それを行う方法を提案しましたが、複雑すぎるようです。関数を再実装しましたが、コードが正しいかどうか、または見逃したかどうか疑問に思っています何か...

次に、then()関数に渡される未来はvoidである可能性があるため、実際にはthen()の2つの実装が必要です。 1つはTを返す先物用で、もう1つはvoidを返す先物用です。

最後に、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));
}
_
29
Roman Kutlak

インターフェイスを簡素化するために、Herbがconcurrent<T>実装で行ったのと同様に、実装内でvoid問題を「非表示」にします。 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));
}
4
eladidan

.then()へのこのアプローチの問題は、2つのスレッド(コストがかかる)を同時に生成し、2番目のスレッドがfuture.get/waitでブロックすることです(もちろん、最初のスレッドが十分に長く実行される場合)。 、ワークキューを使用して、ジョブの実行順序をシリアル化する(および既存のスレッドをリサイクルする)ことをお勧めします。良いスレッドプールパターンの実装を探すだけです

3
barney

いいえ、正しくありません。 .get()の戻り値を継続に渡すと、.get()から伝播された例外を処理できなくなります。 boost.threadの場合と同様に、futureをcontinueに渡し、.get()を手動で呼び出す必要があります。

1
pal