c++11コンカレントライブラリのスレッド同期
7659 ワード
じょうけんへんすう
std::mutex _mutex;
std::condition_variable _cv;
std::deque<:string> _data;
void thread_process_data()
{
while(1){
std::unique_lock<:mutex> lk(_mutex);
_cv.wait(lk, [](){return !_data.empty();});
std::string str = _data.front();
_data.pop();
lk.unlock();
do_something(str);
}
}
void thread_produce_data()
{
while(1){
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
{
std::lock_guard<:mutex> lk(_mutex);
_data.push("hello cv");
}
_cv.notify_one();
}
}
待機条件のスレッド処理プロセス:
std::unique_lock<:mutex/>
を取得する.wait
(wait_for
またはwait_until
)を実行し、これらの関数の呼び出しは、反発ロックを原子的に解放し、スレッドの実行を一時停止する.std::unique_を使用するstdではなくlock::lock_guardの原因は2つあります.
1、待機中のスレッドは、待機中に反発ロックを解除し、待機後に再びロックしなければならないが、std::lock_guardはこの柔軟性を提供しない.
2、wait()の最初のパラメータはstd::unique_である.lockの参照.
起動待ち条件のスレッド:
std::lock_gurad<:mutex/>
notify_one
またはnotify_all
の通知条件が発生すると、待機条件のスレッドが起動する(ロックを持つ必要がないことを通知する)condition variableは、あるイベントが繰り返されるシナリオに適用され、あるシナリオではスレッドが1回のイベントを真に待つだけで、その後、このイベントの発生を永遠に待つことはありません.
future
asyncとfuture
asyncとthreadの違い:
asyncのpolicyパラメータ
packaged_taskとfuture
パッケージlambda
void task_lambda()
{
std::packaged_task task([](int a, int b) {
return std::pow(a, b);
});
std::future result = task.get_future();
// std::pow(2,9)
task(2, 9);
std::cout << "task_lambda:\t" << result.get() << '
';
}
パッケージbind
int f(int x, int y) { return std::pow(x,y); }
void task_bind()
{
std::packaged_task task(bind(f,1,2));
std::future result = task.get_future();
// std::pow(2,9)
task(2, 9);
std::cout << "task_bind:\t" << result.get() << '
';
}
スレッド関数として
int f(int x, int y) { return std::pow(x,y); }
void task_thread()
{
std::packaged_task task(f);
std::future result = task.get_future();
// std::pow(2,9)
std::thread t(std::move(task), 2, 9);
std::cout << "task_thread:\t" << result.get() << '
';
}
同等:
void equal_to_task_thread()
{
std::future result = std::async(std::launch::async, f, 2, 9);
std::cout << "equal_to_async:\t" << result.get() << '
';
}
promiseとfuture
std::promise
は、後で関連するstd::future
オブジェクトを介して値を読み取ることができる値(タイプT)を設定する方法を提供する.ペアはfuture
およびpromise
を使用し、結果を待つスレッドはfuture::wait()
またはfuture::get()
でブロックされる可能性があり、データを提供するスレッドはペアのpromise
を使用して関連する値を設定し、future
を準備することができる.一般的なパターンは次のとおりです.
void do_work(arg, std::promise promise_arg)
{
do_something();
promise_arg.set_value(T);
}
int main()
{
// promise
std::promise one_promise;
// future
std::future one_future = one_promise.get_future();
//promise
std::thread work_thread(do_work, some_arg, std::move(one_promise));
//
one_future.wait();
//
std::cout << "result=" << one_future.get() << '
';
work_thread.join();
}
異常とfuture
extern std::promise some_promise;
try
{
some_promise.set_value(calculate_value());
}
catch(...)
{
//1 current_exception calculate_value()
//2 set_exception()
some_promise.set_exception(std::current_exception());
//
//some_promise.set_exception(std::copy_exception(std::logic_error("foo ")));
}
std::futureモデルは非同期結果に対して一意の所有権を持ち、1つのスレッドだけが非同期結果(getを介して)を抽出することができ、get()を最初に呼び出した後、抽出する値はもうありません.
std::futureはmoveableであり、非同期結果に対する一意の所有権はfutureインスタンス間で移行することができる(移動によって意味を構築する)が、毎回1つのインスタンスだけが特定の非同期結果を参照する.でもstd::shared_futureインスタンスはcopyableなので、shared_を複数作成できます.futureオブジェクトは同じ関連状態を参照する.
優先的な方法は、オブジェクトのコピーを取得し、各スレッドに独自のコピーにアクセスさせることです.各スレッドが独自のstd::shared_を通過する場合futureオブジェクトが共有非同期状態にアクセスすると、複数のスレッドからアクセスするのは安全です.
std::promise p;
std::future f = p.get_future();
// shared_future :
std::shared_future sf(f); //error
std::shared_future sf(std::move(f)); //move
// :
std::shared_future sf = f.share();
// :
std::shared_future sf(std::move(p.get_future()));
assert(!f.valid());
assert(sf.valid());