C++11:なぜ std::condition_variable は std::unique_lock を使用するのですか?
質問
の役割について少し混乱しています。
std::unique_lock
で作業しているときに
std::condition_variable
. 私が理解した限りでは
ドキュメント
,
std::unique_lock
は基本的に肥大化したロックガードで、2つのロック間で状態を入れ替えることが可能です。
私はこれまで
pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
を使用してきました(posixではSTLはこれを使用するのでしょう)。これはロックではなく、ミューテックスを取ります。
ここでの違いは何でしょうか?というのは
std::condition_variable
が扱うのは
std::unique_lock
を最適化するのですか?もしそうなら、具体的にどのように速くなるのでしょうか?
どのように解決するには?
<ブロッククオート技術的な理由はないのですか?
cmeerwさんの回答は技術的な理由を述べていると思うので、upvotedしました。 それを見ていきましょう。 委員会が、以下のように決定したと仮定しましょう。
condition_variable
を待つことにしたとします。
mutex
. その設計を用いたコードを以下に示します。
void foo()
{
mut.lock();
// mut locked by this thread here
while (not_ready)
cv.wait(mut);
// mut locked by this thread here
mut.unlock();
}
これはまさに、ある
はいけません。
を使用します。
condition_variable
. でマークされた領域では
// mut locked by this thread here
には例外安全性の問題があり、それは深刻なものです。 もしこれらの領域で例外が投げられたら(あるいは
cv.wait
自体で)例外が発生した場合、例外をキャッチしてロックを解除するための try/catch がどこかに組み込まれていなければ、ミューテックスのロック状態が漏えいしてしまいます。 しかし、それはプログラマーに書かせるコードを増やすだけです。
プログラマが例外安全コードの書き方を知っていて、例外をキャッチするために
unique_lock
を使うことを知っているとします。 今、コードはこのようになります。
void foo()
{
unique_lock<mutex> lk(mut);
// mut locked by this thread here
while (not_ready)
cv.wait(*lk.mutex());
// mut locked by this thread here
}
これでだいぶ良くなりましたが、まだあまり良い状況とは言えません。 その
condition_variable
インタフェースは、プログラマにわざわざ動作させるようなことをさせています。 もし、ヌルポインタのデリファレンスが発生する可能性があり、その場合
lk
が誤ってmutexを参照しない場合、nullポインタを参照する可能性があります。 そして
condition_variable::wait
のロックがこのスレッドのものであることを確認する方法はありません。
mut
.
あ、そういえば、プログラマが間違った
unique_lock
メンバ関数を選んでしまうという危険もあります。
*lk.release()
はここで悲惨なことになります。
では、実際にどのようにコードが書かれているのかを見てみましょう。
condition_variable
を受け取る API がどのように書かれているかを見てみましょう。
unique_lock<mutex>
:
void foo()
{
unique_lock<mutex> lk(mut);
// mut locked by this thread here
while (not_ready)
cv.wait(lk);
// mut locked by this thread here
}
- このコードは限りなくシンプルです。
- 例外安全です。
-
は
wait
関数はlk.owns_lock()
である場合は例外をスローします。false
.
のAPI設計を推進した技術的な理由です。
condition_variable
.
さらに
condition_variable::wait
は
lock_guard<mutex>
なぜなら
lock_guard<mutex>
はどのように言うのでしょう。 私はこのミューテックスのロックを
lock_guard<mutex>
が破壊されるまで、このミューテックスのロックを所有します。 しかし、あなたが
condition_variable::wait
を呼び出すと、暗黙のうちにミューテックスのロックを解放してしまいます。 ですから、その動作は
lock_guard
のユースケース/ステートメントと矛盾します。
私たちが必要としたのは
unique_lock
これは、関数からロックを返したり、コンテナに入れたり、非スコープのパターンでミューテックスを例外的に安全にロック/アンロックしたりできるようにするためで、そのため
unique_lock
は自然な選択でした。
condition_variable::wait
.
更新
bamboonが下のコメントで、私が対照的であることを提案しました。
condition_variable_any
を対比させることを提案されたので、それを実行します。
質問です。
なぜ
condition_variable::wait
はテンプレート化されていないので、任意の
Lockable
を渡すことができるのですか?
回答
それは本当にクールな機能です。 たとえば
この論文
で待機するコードを示しています。
shared_lock
(rwlock)を条件変数上で共有モードで待つコードを実演しています (posixの世界では前代未聞ですが、それでも非常に有用です)。 しかし、この機能はより高価です。
そこで委員会はこの機能を持つ新しい型を導入しました。
`condition_variable_any`
このように
condition_variable
アダプタ
を待つことができます。
任意の
ロック可能な型。 もしそれがメンバー
lock()
と
unlock()
であれば、問題ありません。 の適切な実装は
condition_variable_any
を必要とします。
condition_variable
データメンバと
shared_ptr<mutex>
のデータメンバがあります。
この新しい機能は、あなたの基本的な
condition_variable::wait
よりも高価であり、また
condition_variable
は低レベルのツールであるため、この非常に便利だが高価な機能は別のクラスに置かれ、使用する場合にのみ代金を支払うようにしました。
関連
-
[解決済み] 非静的データメンバの無効な使用
-
[解決済み】エラー:free(): 次のサイズが無効です(fast)。
-
[解決済み] explicit キーワードの意味は?
-
[解決済み] using namespace std;」はなぜバッドプラクティスだと言われるのですか?
-
[解決済み] 要素ごとの加算は、結合ループよりも分離ループの方がはるかに高速なのはなぜですか?
-
[解決済み] C++11では、標準化されたメモリモデルが導入されました。その意味するところは?そして、C++プログラミングにどのような影響を与えるのでしょうか?
-
[解決済み] スマートポインターとは何ですか?
-
[解決済み] なぜ、オブジェクトそのものではなく、ポインタを使用しなければならないのですか?
-
[解決済み] 0.1fを0にすると、なぜ10倍もパフォーマンスが落ちるのですか?
-
[解決済み】 std::unique_lock<std::mutex> と std::lock_guard<std::mutex> のどちらを選ぶ?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】coutはstdのメンバではない
-
[解決済み】C++でランダムな2倍数を生成する
-
[解決済み] string does not name a type Errorが発生するのはなぜですか?
-
[解決済み】IntelliSense:オブジェクトに、メンバー関数と互換性のない型修飾子がある
-
[解決済み】エラー:strcpyがこのスコープで宣言されていない
-
[解決済み】エラー。switchステートメントでcaseラベルにジャンプする
-
[解決済み】#include<iostream>は存在するのですが、「識別子 "cout "は未定義です」というエラーが出ます。なぜですか?
-
[解決済み] [Solved] インクルードファイルが開けません。'stdio.h' - Visual Studio Community 2017 - C++ Error
-
[解決済み】標準ライブラリにstd::endlに相当するタブはあるか?
-
[解決済み] 変数サイズのオブジェクトが初期化されないことがある c++