使用する適切な_std::thread
_クラスを決定するのに役立つ、いくつかのヒューリスティックを確立しようとしています。
私が理解しているように、最高レベル(最も使いやすいが柔軟性が最も低い)から最低レベルまで、次のようになります。
いつ使用するか最初の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を使用することを選択するのはいつですか?
リンクの回答(例:stdを使用)ではなく、経験則(上記の3.の???を入力)のようなアプリケーションレベルの回答を探しています。 ::いくつかのライブラリメカニズムを実装することを約束します)、_std::thread
_。の初心者ユーザーに適切なクラスを選択する方法をより簡単に説明できます
言い換えれば、_std::promise
_で何ができるのか、他のメカニズムではcannotできるという便利な例があると便利です。
[〜#〜] answer [〜#〜]
_std::future
_は奇妙な獣です。一般に、その値を直接変更することはできません。
その値を変更できる3つのプロデューサーは次のとおりです。
std::async
_。これにより、_std::future
_インスタンスが返されます。std::packaged_task
_は、スレッドに渡されると、そのコールバックを呼び出し、それによってその_std::future
_に関連付けられた_std::packaged_task
_インスタンスを更新します。このメカニズムにより、プロデューサーの早期バインドが可能になりますが、後で呼び出すことができます。std::promise
_。これにより、関連する_std::future
_をset_value()
呼び出しで変更できます。 _std::future
_の変更を直接制御することで、複数のプロデューサーが存在する場合にデザインがスレッドセーフであることを確認する必要があります(必要に応じて_std::mutex
_を使用します)。私は思う SethCarnegieの答え :
簡単に考えると、値を返すか、promiseを使用して未来を設定できます。 futureには決まった方法がありません。その機能はpromiseによって提供されます。
いつpromiseを使用するかを明確にするのに役立ちます。ただし、使用法によっては、promiseにさまざまなスレッドからアクセスできる可能性があるため、_std::mutex
_が必要になる場合があることに注意する必要があります。
また、 DavidのRodriguezの答え も優れています:
通信チャネルのコンシューマー側はstd :: futureを使用して共有状態からデータを消費し、プロデューサースレッドはstd :: promiseを使用して共有状態に書き込みます。
しかし、別の方法として、結果のstlコンテナーで_std::mutex
_を使用し、コンテナーを操作するために1つのスレッドまたはプロデューサーのスレッドプールを使用しないのはなぜですか?代わりに、_std::promise
_を使用すると、結果のstlコンテナーと比較して、読みやすさが向上するだけでなく、何を購入できますか?
コントロールは、_std::promise
_バージョンの方が優れているようです。
次のグーグルテストはhelgrindとdrdの両方に合格し、単一のプロデューサーで、wait()を使用して、ミューテックスが不要であることを確認します。
[〜#〜] test [〜#〜]
_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() );
}
_
他のpromise
の代わりにを使用することを選択せず、promise
を使用してfulfilla future
他の人と組み合わせて。 cppreference.com のコードサンプルは、4つすべてを使用する例を示しています。
#include <iostream>
#include <future>
#include <thread>
int main()
{
// future from a packaged_task
std::packaged_task<int()> task([](){ return 7; }); // wrap the function
std::future<int> f1 = task.get_future(); // get a future
std::thread(std::move(task)).detach(); // launch on a thread
// future from an async()
std::future<int> f2 = std::async(std::launch::async, [](){ return 8; });
// future from a promise
std::promise<int> p;
std::future<int> f3 = p.get_future();
std::thread( [](std::promise<int>& p){ p.set_value(9); },
std::ref(p) ).detach();
std::cout << "Waiting...";
f1.wait();
f2.wait();
f3.wait();
std::cout << "Done!\nResults are: "
<< f1.get() << ' ' << f2.get() << ' ' << f3.get() << '\n';
}
プリント
待っています...完了です!
結果は次のとおりです。789
先物は、結果を取得するために3つのスレッドすべてで使用され、promise
は、戻り値以外の手段でfuture
を満たすために3番目のスレッドで使用されます。また、単一のスレッドは、future
sを介して異なる値を持つ複数のpromise
sを満たすことができますが、それ以外の場合は実行できません。
簡単に考えると、値を返すか、future
を使用してpromise
を設定できます。 future
にはset
メソッドがありません。その機能はpromise
によって提供されます。状況が許すものに基づいて、必要なものを選択します。
2つのレベルの非同期がある場合は、promiseを使用する必要があります。例えば:
void fun()
{
std::promise<int> p;
std::future<int> f = p.get_future();
std::future<void> f2;
auto f3 = std::async([&]{
// Do some other computation
f2 = std::async([&]{ p.set_value(42);});
// Do some other work
});
// Do some other work
// Now wait for the result of async work;
std::cout << f.get();
// Do some other work again
// Wait for async threads to complete
f3.wait();
f2.wait();
}