std::thread
使用する適切なクラスを決定するのに役立ついくつかのヒューリスティックを確立しようとしています。
私が理解しているように、最高レベル(最も使いやすいが、柔軟性が最も低い)から最低レベルまで、次のものがあります。
- std::async with/std::future (std::shared_future) (1 回限りのスロー アウェイ プロデューサー スレッド非同期で実行する場合)
- std::packaged_task (プロデューサーを割り当てたいが、スレッドへの呼び出しを延期する場合)
- std::promise (???)
最初の 2 つをいつ使用するかについては十分に把握していると思いますが、についてはまだ不明ですstd::promise
。
std::future
呼び出しと組み合わせてstd::async
、作成中のコールバック/ファンクター/ラムダを非同期呼び出しに効果的に変換します (定義により、すぐに戻ります)。単一のコンシューマーはstd::future::get()
、ブロッキング呼び出しである を呼び出して、その結果を取得できます。
std::shared_future
は、複数のコンシューマを許可する単なるバージョンです。
std::future
値をプロデューサ コールバックにバインドしたいが、実際の呼び出しを後で (タスクをスポーン スレッドに関連付けるとき) 延期したい場合は、std::packaged_task
が正しい選択です。しかし、一般的なケースでは、 に対応std::future
する はstd::package_task
複数のスレッドからアクセスされる可能性があるため、std::mutex
. std::async
を使用すると、最初のケースでは、ロックについて心配する必要がないことに注意してください。
promise に関するいくつかの興味深いリンクを読んだので、そのメカニズムとその設定方法は理解できたと思いますが、私の質問は、他の 3 つよりも promise を使用することを選択するのはいつですか?
リンクの答えとは対照的に、経験則(上記の3.で???を埋める)のようなアプリケーションレベルの答えをもっと探しています(たとえば、 std::promise を使用していくつかのライブラリを実装します)メカニズム)、したがって、適切なクラスを選択する方法を の初心者ユーザーに簡単に説明できますstd::thread
。
言い換えれば、他のメカニズムではstd::promise
できなくて、私が でできることの有用な例があればいいのにと思います。
答え
Astd::future
は奇妙な獣です。一般に、その値を直接変更することはできません。
その値を変更できる 3 つのプロデューサーは次のとおりです。
std::async
std::future
インスタンスを返す非同期コールバックを介して。std::packaged_task
スレッドに渡されると、そのコールバックが呼び出され、それにstd::future
関連付けられたインスタンスが更新されますstd::packaged_task
。このメカニズムにより、プロデューサの早期バインディングが可能になりますが、後で呼び出すことができます。std::promise
、これにより、その呼び出しstd::future
を通じて関連付けられたものを変更できます。set_value()
このように a の変更を直接制御することでstd::future
、複数のプロデューサーが存在する場合に設計がスレッドセーフであることを確認する必要があります (std::mutex
必要に応じて使用します)。
SethCarnegieの答えだと思います:
これを考える簡単な方法は、値を返すか、Promise を使用して未来を設定できるということです。future には設定方法がありません。その機能は約束によって提供されます。
promise をいつ使用するかを明確にするのに役立ちます。ただしstd::mutex
、使用法によっては異なるスレッドから promise にアクセスできる可能性があるため、 a が必要になる場合があることに注意する必要があります。
また、デビッドのロドリゲスの答えも優れています。
通信チャネルのコンシューマー側は std::future を使用して共有状態からデータを消費し、プロデューサー スレッドは std::promise を使用して共有状態に書き込みます。
しかし、別の方法として、単純std::mutex
に結果の stl コンテナーで a を使用し、プロデューサーの 1 つのスレッドまたはスレッドプールをコンテナーで動作させないのはなぜでしょうか? std::promise
結果の stl コンテナーと比べて読みやすさが向上する以外に、代わりに を使用すると何が得られるのでしょうか?
コントロールはstd::promise
バージョンの方が優れているようです:
- wait() は、結果が生成されるまで、特定の未来をブロックします
- プロデューサー スレッドが 1 つしかない場合、ミューテックスは必要ありません。
次の google-test は、helgrind と drd の両方に合格し、単一のプロデューサーで、wait() を使用すると、ミューテックスが不要であることを確認します。
テスト
static unsigned MapFunc( std::string const& str )
{
if ( str=="one" ) return 1u;
if ( str=="two" ) return 2u;
return 0u;
}
TEST( Test_future, Try_promise )
{
typedef std::map<std::string,std::promise<unsigned>> MAP;
MAP my_map;
std::future<unsigned> f1 = my_map["one"].get_future();
std::future<unsigned> f2 = my_map["two"].get_future();
std::thread{
[ ]( MAP& m )
{
m["one"].set_value( MapFunc( "one" ));
m["two"].set_value( MapFunc( "two" ));
},
std::ref( my_map )
}.detach();
f1.wait();
f2.wait();
EXPECT_EQ( 1u, f1.get() );
EXPECT_EQ( 2u, f2.get() );
}