425

2 つの使用例があります。

A. 2 つのスレッドのキューへのアクセスを同期させたい。

B. 2 つのスレッドのキューへのアクセスを同期し、条件変数を使用したい。スレッドの 1 つが、コンテンツが他のスレッドによってキューに格納されるのを待つためです。

AI の使用例については、 を使用したコード例を参照してくださいstd::lock_guard<>。BI の使用例については、 を使用したコード例を参照してくださいstd::unique_lock<>

2 つの違いは何ですか?どのユースケースでどちらを使用する必要がありますか?

4

7 に答える 7

412

違いは、ロックとロック解除ができることですstd::unique_lockstd::lock_guard建設時に一度だけロックされ、破壊時にロックが解除されます。

したがって、ユース ケース B の場合std::unique_lock、条件変数には必ず a が必要です。A の場合、ガードを再ロックする必要があるかどうかによって異なります。

std::unique_lockたとえば、ミューテックスをすぐにロックせずに構築できますが、RAII ラッパーを構築できます (こちらを参照)。

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_guardstd::unique_lockは と同じです。したがって、上記の場合、 に置き換えることができstd::lock_guardますstd::unique_lock。ただし、std::unique_lockオーバーヘッドが少し増える可能性があります。

最近 (C++17 以降)std::scoped_lockの代わりに を使用する必要があることに注意してくださいstd::lock_guard

于 2013-12-11T10:39:37.150 に答える
148

lock_guardunique_lockほとんど同じです。lock_guardインターフェイスが制限された制限付きバージョンです。

Alock_guardは、その構築から破棄まで常にロックを保持します。はすぐにロックせずに作成でき、存在するunique_lock任意の時点でロックを解除でき、ロックの所有権をあるインスタンスから別のインスタンスに転送できます。

したがってlock_guard、 の機能が必要でない限り、常に を使用しますunique_lock。にcondition_variableは が必要unique_lockです。

于 2013-12-11T10:41:08.947 に答える
57

を破壊せずに間にミューテックスlock_guardを手動でできる必要がない限り、使用してください。unlocklock

特に、condition_variableへの呼び出しでスリープ状態になると、そのミューテックスのロックが解除されますwait。そのため、lock_guardここでは a では十分ではありません。

既に C++17 以降を使用している場合は、同じ基本機能を備えたscoped_lockのわずかに改良されたバージョンとして使用することを検討してください。lock_guard

于 2013-12-11T10:39:03.923 に答える
11

と の間には特定の共通点がlock_guardありunique_lock、特定の違いがあります。

ただし、質問のコンテキストでは、コンパイラはlock_guard条件変数と組み合わせて使用​​することを許可していません。これは、スレッドが条件変数で待機を呼び出すと、ミューテックスが自動的にロック解除され、他のスレッド/スレッドが通知し、現在のスレッドがが呼び出される (待機が終了する) と、ロックが再取得されます。

この現象は の原則に反していlock_guardます。lock_guard建設は 1 回のみ、破壊は 1 回のみです。

したがってlock_guard、条件変数と組み合わせて使用​​することはできませんが、使用することはunique_lockできます (unique_lock数回ロックおよびロック解除できるため)。

于 2014-09-16T12:18:14.813 に答える
-5

他の人が言及したように、 std::unique_lock はミューテックスのロック状態を追跡するため、ロックの構築後までロックを延期し、ロックの破棄前にロックを解除できます。std::lock_guard はこれを許可しません。

std::condition_variable 待機関数が、unique_lock だけでなく lock_guard もとらない理由はないようです。なぜなら、待機が終了するたびに (何らかの理由で) ミューテックスが自動的に再取得されるため、セマンティック違反が発生しないためです。ただし、標準によれば、条件変数で std::lock_guard を使用するには、std::condition_variable の代わりに std::condition_variable_any を使用する必要があります。

編集: 「pthreads インターフェイス std::condition_variable と std::condition_variable_any の使用は同一である必要があります」を削除しました。gccの実装を見ると:

  • std::condition_variable::wait(std::unique_lock&) は、unique_lock が保持するミューテックスに関して、基礎となる pthread 条件変数で pthread_cond_wait() を呼び出すだけです (したがって、lock_guard に対しても同様に同じことができますが、そうではありません。提供していません)
  • std::condition_variable_any は、mutex ロックではないオブジェクトを含め、ロック可能なオブジェクトで動作します (したがって、プロセス間セマフォでも動作する可能性があります)。
于 2013-12-17T23:54:22.653 に答える