この質問と大まかに関連しています: Are std::thread pooled in C++11? . 質問は異なりますが、意図は同じです。
質問 1: 高価なスレッドの作成を避けるために、独自の (またはサードパーティのライブラリ) スレッド プールを使用することは依然として理にかなっていますか?
他の質問の結論は、プールされることを当てstd::thread
にできないということでした (そうかもしれないし、そうでないかもしれません)。ただし、std::async(launch::async)
プールされる可能性ははるかに高いようです。
標準で強制されているとは思いませんが、スレッドの作成が遅い場合、すべての優れた C++11 実装でスレッド プーリングが使用されると思います。新しいスレッドを作成するのに費用がかからないプラットフォームでのみ、常に新しいスレッドを生成することが期待されます。
質問 2: これは私の考えですが、それを証明する事実はありません。私は間違っているかもしれません。勝手な推測ですか?
最後に、スレッドの作成を次のように表現できると思う方法を最初に示すサンプルコードをいくつか提供しましたasync(launch::async)
。
例 1:
thread t([]{ f(); });
// ...
t.join();
になる
auto future = async(launch::async, []{ f(); });
// ...
future.wait();
例 2: スレッドを起動して忘れる
thread([]{ f(); }).detach();
になる
// a bit clumsy...
auto dummy = async(launch::async, []{ f(); });
// ... but I hope soon it can be simplified to
async(launch::async, []{ f(); });
質問 3:バージョンよりもasync
バージョンの方が好みthread
ですか?
残りはもはや質問の一部ではありませんが、明確にするためだけです:
戻り値をダミー変数に代入する必要があるのはなぜですか?
残念ながら、現在の C++11 標準では、 の戻り値をキャプチャする必要がありますstd::async
。そうしないと、デストラクタが実行され、アクションが終了するまでブロックされます。これは、標準のエラーと見なされる人もいます (たとえば、Herb Sutter による)。
cppreference.com のこの例は、それをうまく示しています。
{
std::async(std::launch::async, []{ f(); });
std::async(std::launch::async, []{ g(); }); // does not run until f() completes
}
別の説明:
スレッドプールには他の正当な用途があることは知っていますが、この質問では、高価なスレッド作成コストを回避するという側面にのみ関心があります。
特にリソースをより細かく制御する必要がある場合など、スレッド プールが非常に役立つ状況がまだあると思います。たとえば、サーバーは、高速な応答時間を保証し、メモリ使用量の予測可能性を高めるために、一定数の要求のみを同時に処理することを決定する場合があります。ここでは、スレッドプールは問題ないはずです。
スレッド ローカル変数は、独自のスレッド プールの引数にもなる可能性がありますが、実際に関連するかどうかはわかりません。
std::thread
スレッドローカル変数を初期化せずに開始する新しいスレッドを作成します。多分これはあなたが望むものではありません。- によって生成され
async
たスレッドでは、スレッドが再利用された可能性があるため、私にはやや不明です。私の理解では、スレッド ローカル変数がリセットされる保証はありませんが、間違っている可能性があります。 - 一方、独自の (固定サイズの) スレッド プールを使用すると、本当に必要な場合に完全に制御できます。