4

std::launch::async ポリシーで std::async を起動すると、新しいスレッドですべての非同期タスクを開始するべきではありませんか? 現時点では、新しい非同期タスクが作業を完了したばかりのスレッドに移動しているように見えます。コンパイラとして VC11 を使用しています。新しいワーカー (ワーカーが ID 34500 のスレッドを複数回取得するなど) が std::async で起動されたときの出力からわかるように、以前に終了したスレッドで開始されます。std::async の私の理解は間違っていますか、それとも根本的な作業盗用キューまたはそのようなものがありますか?

Worker (ID=24072) starting.
Worker (ID=34500) starting.
Worker (ID=32292) starting.
Worker (ID=31392) starting.
Worker (ID=17976) starting.
Worker (ID=31580) starting.
Worker (ID=33512) starting.
Worker (ID=33804) starting.
Worker 32292 finished.
Worker (ID=32292) starting.
Worker 17976 finished.
Worker (ID=17976) starting.
Worker 31580 finished.
Worker (ID=31580) starting.
Worker 34500 finished.
Worker (ID=34500) starting.
Worker 34500 finished.
Worker (ID=34500) starting.
Worker 32292 finished.
Worker (ID=32292) starting.
Worker 17976 finished.
Worker (ID=17976) starting.
Worker 34500 finished.
Worker 17976 finished. 
Worker 31580 finished.
Worker 32292 finished.
Worker 33804 finished.
Worker 31392 finished.
Worker 33512 finished.
Worker 24072 finished.
4

2 に答える 2

11

ポリシーで起動std::asyncした場合std::launch::async、すべての非同期タスクを新しいスレッドで開始するべきではありませんか?

仕様では、非同期操作を「実行の新しいスレッドであるかのように」実行する必要があります (C++11 §30.6.8/11)。ここで重要な言葉は次のとおり です

動作が新しいスレッドが作成された場合と同じである場合にのみ、既に実行中のワーカー スレッドを再利用できます。これは、たとえば、thread_local単一スレッドで実行される非同期操作間で、ストレージ クラスの変数をリセットする必要があることを意味します。

スレッド識別子は実行中のスレッドのみを一意に識別するため、スレッド識別子をリセットする必要はありません。スレッドが終了すると、別のスレッドが最初のスレッドの識別子で開始される場合があります。

根底にあるワークスチールキューまたはそのようなものはありますか?

これは実装固有です。C++11 スレッド サポート ライブラリの Visual C++ 2012 実装は、コンカレンシー ランタイム (ConcRT)の上に構築されており、ワークスティーリング タスク スケジューラが含まれています。

于 2012-07-14T01:34:13.060 に答える
6

James は正しく、1 つ訂正があります。 Microsoft による launch::async の実装は正しくありません。これについては、Redmondの C++ 同時実行ワーキング グループによって詳細に議論されました。Visual C++ 2012 はまだベータ版であるため、標準に準拠するように実装を変更する可能性があります。

于 2012-07-14T17:38:28.800 に答える