それはこの質問に緩く関連しています:std :: threadは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
初期化されたスレッドローカル変数なしで、startsで新しいスレッドを作成します。多分これはあなたが望むものではありません。- によって生成され
async
たスレッドでは、スレッドが再利用された可能性があるため、私には多少不明確です。私の理解では、スレッドローカル変数がリセットされるとは限りませんが、間違っている可能性があります。 - 一方、独自の(固定サイズ)スレッドプールを使用すると、本当に必要な場合に完全に制御できます。
std::async()
。それらがスレッドプール内の自明でないthread_localデストラクタをどのようにサポートするかを知りたいと思っています。
launch::async
場合、それがlaunch::deferred
非同期であるかのように扱われ、決して実行されないことがわかりました。つまり、そのバージョンのlibstdc ++は「選択」します。強制されない限り、常に据え置きを使用する。
std::async
パフォーマンスにとっては美しいものでした。スレッドプールによって自然に支えられた、標準の短期実行タスク実行システムであった可能性もあります。現時点でstd::thread
は、スレッド関数が値を返すことができるようにするためにいくつかのがらくたが追加されているだけです。ああ、そして彼らはstd::function
完全に仕事をオーバーラップする冗長な「据え置き」機能を追加しました。
std::async(launch::async)
プールされる可能性ははるかに高いようです。」いいえ、それはstd::async(launch::async | launch::deferred)
プールされる可能性があると思います。ただでlaunch::async
タスクは関係なく、他のタスクが実行されているものの新しいスレッドに発売されることになっています。ポリシーlaunch::async | launch::deferred
を使用すると、実装はどのポリシーを選択できるようになりますが、より重要なのは、どのポリシーの選択を遅らせるかです。つまり、スレッドプール内のスレッドが使用可能になるまで待機してから、非同期ポリシーを選択できます。