12

私はstd::async、将来のコンパイラの実装でそれをどのように使用すべきかについて考えてきました。ただし、現在、設計上の欠陥のように感じられるものに少し行き詰まっています。

std::asyncかなり実装に依存しており、おそらく 2 つのバリアントがlaunch::asyncあります。1 つはタスクを新しいスレッドに起動し、もう 1 つはスレッド プール/タスク スケジューラを使用します。

ただし、これらのバリアントのどれを実装するためstd::asyncに使用するかによって、使用方法は大きく異なります。

「スレッドプール」ベースのバリアントの場合、オーバーヘッドをあまり気にせずに多くの小さなタスクを起動できますが、ある時点でタスクの 1 つがブロックされたらどうなるでしょうか?

一方、「新しいスレッドを起動する」バリアントは、タスクをブロックしても問題は発生しませんが、タスクの起動と実行のオーバーヘッドは非常に高くなります。

thread-pool: +low-overhead, -決してブロックしない

新しいスレッドを立ち上げます: +ブロックで細かい、-高いオーバーヘッド

したがって、基本的には実装に応じて、使用方法はstd::async非常に慎重になります。あるコンパイラで問題なく動作するプログラムがある場合、別のコンパイラではひどく動作する可能性があります。

これは設計によるものですか?または、何か不足していますか?私と同じように、これを大きな問題と考えますか?

現在の仕様ではstd::oversubscribe(bool)、実装に依存しないstd::async.

編集: 私が読んだ限りでは、C++ 11 標準ドキュメントには、送信されたタスクstd::asyncがブロックされるかどうかに関するヒントはありません。

4

2 に答える 2

11

std::asyncstd::launch::asyncタスクは「あたかも新しいスレッドのように」実行するポリシーで起動されたため、スレッド プールは実際にはサポートされていません --- ランタイムは、各タスクの実行の間にすべてのスレッド ローカル変数を破棄して再作成する必要がありますが、これはそうではありません。簡単です。

これは、 のポリシーで開始されたタスクが同時に実行されることを期待できることも意味しますstd::launch::async。起動の遅延が発生する可能性があり、実行中のスレッドがプロセッサよりも多い場合はタスクの切り替えが発生しますが、スレッドが実行されている必要があり、あるスレッドが別のスレッドを待機しているという理由だけでデッドロックすることはありません。

実装は、タスクをスレッド プールで実行できるようにする拡張機能を提供することを選択する場合があります。その場合、セマンティクスを文書化するのはその実装次第です。

于 2012-02-20T15:42:44.510 に答える
1

私は、実装が新しいスレッドを起動し、スレッド プールを標準化する C++ の将来のバージョンに任せることを期待しています。スレッドプールを使用する実装はありますか?


MSVC は当初、同時実行ランタイムに基づいてスレッド プールを使用していました。STL Fixes In VS 2015, Part 2によると、これは削除されました。C++ 仕様では、実装者が巧妙なことを行う余地がいくらか残されていましたが、このスレッド プーリングの実装には十分な余地が残されていなかったと思います。特に、仕様ではthread_localオブジェクトを破棄して再構築する必要がありましたが、ConcRT を使用したスレッド プーリングではそれがサポートされていなかったと思います。

于 2012-02-20T15:42:10.073 に答える