web-dev-qa-db-ja.com

オブジェクトデストラクタで非同期タスクを待つのは良いアプローチですか?

私は現在、内部でいくつかの非同期タスクを使用してクラスに取り組んでいます。実際、非同期実行にいくつかのタスクを委任する必要があり、クラスが破棄される前にすべてのタスクが完了していることを確認する必要があります。クラスデストラクタ内で終了するまで、すべてのタスクを待機することを考えていました。 C++言語のstdライブラリ内で使用されている既存のアプローチを調査しています。私は非同期実装のさまざまな方法に興味を持っていました。

たとえば、_std::thread_は、デストラクタ内で何も待機しません。次のコードは、実行可能な終了で失敗します。

_void sleep() {
    std::this_thread::sleep_for(std::chrono::seconds(5));
}

void execute_thead() {
    auto thread = std::thread(&sleep);
}
_

そのため、作成したスレッドに対してjoin()の呼び出しを強制しました。全体的に、「Hey!非同期タスクを作成したので、親切にして手動で待機してください」のように、私にはもっとはっきりと見えます。ただし、join()またはdetach()の呼び出しを忘れた場合に例外をスローすると、予期しない結果になる場合があります。

一方、_std::async_を見てみましょう。次のコードは、将来のデストラクタ内で結果を待機します。

_void execute_async() {
    auto result = std::async(std::launch::async, &sleep);
}
_

すべてのタスクが完了するまで待機している間、コードコードがスコープ外に出るとハングすることは明らかではありません。コードのリファクタリングまたは最適化中に実際のボトルネックを見つけるのは難しい場合があります。しかし、利点は、未完了のタスクを気にする必要がないことです。

注意してください、ここではスレッドベースの戦略とタスクベースの戦略については話していません。暗黙の待機が明示的な待機よりも優れているかどうかを正式に尋ねていますが、これは非同期コードを作成するための全体的な良い方法ですか?.

5
Liastre

オブジェクトデストラクタで非同期タスクを待つのは良いアプローチですか?

個人的に私はその質問に "No"で答えます。
その答えの理由は簡単です。この質問が発生することはありません。

その質問が発生する状況に遭遇した場合は、コード設計に問題があります。非同期タスクでは、オブジェクトが終了するまでオブジェクトが生存し続ける必要はありません。その場合、タスクを待つ必要はありません。または、タスクが完了する前にオブジェクトが死ぬことは決してないはずです。その場合、問題も発生しません。

1
Mecki

非同期タスクのようなオブジェクトがデストラクタにタスクの完了を待機させる主な理由は、notであるため、誰かが簡単に「非同期」を書き込むことができますすぐに終了するタスク。 safety理由のためにあります。実際、RAIIが他のケースで使用されるのは、まったく同じ安全上の理由によるものです。

これらの2つのケースは同様に悪いです:

int *ptr = new int;
do_something();
delete ptr;
---
thread th(...);
do_something();
th.join();

do_somethingは例外を発生しますか?スレッドthは失われ、スレッドへの接続はすべて床に落ちて忘れられます。 ptrが指すメモリと同じです。

RAIIオブジェクトがそのリソースを解放するようにして、管理されなくなり、手動でクリーンアップする必要があるようにすることは妥当です。これをデフォルトの動作にすることは、はるかに防御が困難です。

つまり、質問は最終的にこれに要約されます:コードはどのようにsafeにしたいですか?

0
Nicol Bolas