2つのユースケースがあります。
A. 2つのスレッドによるアクセスをキューに同期させたいのですが。
B. 2つのスレッドによるキューへのアクセスを同期させ、条件変数を使用します。スレッドの1つが、他のスレッドによってキューに格納されるコンテンツを待機するためです。
ユースケースAでは、 std::lock_guard<>
を使用したコード例を参照してください。ユースケースBでは、 std::unique_lock<>
を使ったコード例を見てください。
両者の違いは何ですか?また、どちらのユースケースでどちらを使用すればよいですか?
違いは、std::unique_lock
をロックおよびロック解除できることです。 std::lock_guard
は構築時に一度だけロックされ、破棄時にロック解除されます。
そのため、ユースケースBでは、条件変数にstd::unique_lock
が必ず必要です。ケースAの場合、それはあなたがガードを再ロックする必要があるかどうかによって異なります。
std::unique_lock
には他の機能があります。例えば:ミューテックスを直ちにロックせずにRAIIラッパーを構築することです( here を参照)。
std::lock_guard
は便利なRAIIラッパーも提供しますが、複数のミューテックスを安全にロックすることはできません。限定された範囲のラッパーが必要な場合に使用できます。例えば、メンバー関数です。
class MyClass{
std::mutex my_mutex;
void member_foo() {
std::lock_guard<mutex_type> lock(this->my_mutex);
/*
block of code which needs mutual exclusion (e.g. open the same
file in multiple threads).
*/
//mutex is automatically released when lock goes out of scope
};
Chmikeによる質問を明確にするために、デフォルトではstd::lock_guard
とstd::unique_lock
は同じです。したがって、上記の場合、std::lock_guard
をstd::unique_lock
に置き換えることができます。ただし、std::unique_lock
には、もう少しオーバーヘッドがあります。
最近ではstd::scoped_lock
の代わりに std::lock_guard
を使うべきです。
lock_guard
とunique_lock
はほとんど同じものです。 lock_guard
は制限されたインターフェースを持つ制限されたバージョンです。
lock_guard
は常にその構造から破壊までロックをかけています。 unique_lock
はすぐにロックすることなく作成することができ、その存在下の任意の時点でロックを解除することができ、そしてロックの所有権をあるインスタンスから別のインスタンスに移すことができます。
そのため、lock_guard
の機能が必要でない限り、常にunique_lock
を使用します。 condition_variable
はunique_lock
を必要とします。
unlock
を破壊することなく、その間のミューテックスを手動でlock
できるようにする必要がない限り、lock_guard
を使用してください。
特にcondition_variable
は、wait
の呼び出しでスリープするときにミューテックスのロックを解除します。だからこそlock_guard
だけでは不十分です。
lock_guard
とunique_lock
の間には共通点がいくつかありますが、違いもあります。
しかし、質問の文脈では、コンパイラーはlock_guard
を条件変数と組み合わせて使用することを許可しません。スレッドが条件変数でwaitを呼び出すと、mutexが自動的にロック解除され、他のスレッドがスレッドが呼び出され(待ち状態から抜け出し)、ロックが再獲得されます。
この現象はlock_guard
の原則に反しています。 lock_guard
は一度だけ構築でき、一度だけ破壊できます。
したがって、lock_guard
を条件変数と組み合わせて使用することはできませんが、unique_lock
を使用することはできます(unique_lock
を何度もロックおよびロック解除できるため)。