std :: lock_guardまたはstd :: scoped_lock?


回答:


125

scoped_lockより厳密に優れたバージョンであるlock_guardすべての(同じデッドロック回避アルゴリズムを使用して、一度にミューテックスの任意の数をロックしていますstd::lock)。新しいコードでは、のみを使用してくださいscoped_lock

lock_guardまだ存在する唯一の理由は、互換性のためです。現在のコードで使用されているため、単に削除することはできません。さらに、その定義を(単項から可変に)変更することは望ましくないことがわかりました。


8
また、クラステンプレートの引数の控除のおかげで、ロック可能な型をリストする必要もありません。
Nicol Bolas

3
@NicolBolas:それは事実ですが、それはにも当てはまりますlock_guard。しかし、それは確かにガードクラスを少し使いやすくします。
Kerrek SB 2017

6
scoped_lockはC ++ 17のみ
Shital Shah

1
c ++ 17であるため、互換性はその存在の特に良い理由です。私はまた、この基準からインクがまだ乾燥しているときは、「絶対に使用してはならない」という絶対主義者の主張には強く反対します。
ポールチャイルズ

88

単一の重要な違いはstd::scoped_lock、可変個のコンストラクターが複数のミューテックスを取ることです。これにより、まるでstd::lock使用されたかのように、デッドロックを回避して複数のミューテックスをロックできます。

{
    // safely locked as if using std::lock
    std::scoped_lock<std::mutex, std::mutex> lock(mutex1, mutex2);     
}

以前は、この回答std::lockを説明したように使用して、安全な方法で複数のミューテックスをロックするために少しダンスをする必要がありました。

スコープロックの追加により、これが使いやすくなり、関連するエラーが回避されます。std::lock_guard非推奨と見なすことができます。の単一引数のケースはstd::scoped_lock特殊化として実装できるため、パフォーマンスの問題の可能性について心配する必要はありません。

GCC 7にはすでにサポートがstd::scoped_lockあり、ここで確認できます

詳細については、標準的なペーパーを読むことをお勧めします


9
たった10分であなた自身の質問に答えました。あなたは本当に知りませんでしたか?
ウォルター


3
それを委員会で取り上げたとき、答えは「何もない」でした。アルゴリズムの退化したケースかもしれませんが、これはまさに正しいことです。あるいは、何かをロックするつもりだったときに、偶然何もロックしない人が十分にいるというのはよくある問題です。よくわかりません。
ハワードヒンナン2017年

3
@HowardHinnant: scoped_lock lk; // locks all mutexes in scope。LGTM。
Kerrek SB 2017

2
@KerrekSB: scoped_lock lk;の新しい省略形ですscoped_lock<> lk;。ありません何のミューテックスが。だからあなたは正しい。;-)
ハワードヒンナン2017年

26

遅い答え、そして大部分は以下に対応します:

std::lock_guard非推奨と見なすことができます。

ミューテックスを1つだけロックする必要があるという一般的なケースでstd::lock_guardは、を使用するよりも少し安全なAPIがありますscoped_lock

例えば:

{
   std::scoped_lock lock; // protect this block
   ...
}

上記のスニペットは、コンパイルしてまったく何もしないため、偶発的な実行時エラーの可能性があります。コーダーはおそらく意味しました:

{
   std::scoped_lock lock{mut}; // protect this block
   ...
}

これでロック/ロック解除されmutます。

lock_guard上記の2つの例で使用された場合、最初の例は実行時エラーではなくコンパイル時エラーであり、2番目の例はを使用するバージョンと同じ機能を備えていますscoped_lock

だから私のアドバイスは、仕事に最も簡単なツールを使うことです:

  1. lock_guard スコープ全体で1つのmutexをロックする必要がある場合。

  2. scoped_lock 正確に1ではない複数のミューテックスをロックする必要がある場合。

  3. unique_lock ブロックの範囲内でロックを解除する必要がある場合(これには、 condition_variable)。

このアドバイス 、0ミューテックスを受け入れないように再設計する必要があることを意味するものではありませscoped_lockscoped_lock空である可能性のある可変テンプレートテンプレートパックを受け入れることが望ましい有効な使用例が存在します。そして、空のケースはすべきではありません何もロックして。

そして、それlock_guardがが非推奨ではない理由です。 scoped_lock unique_lockの機能のスーパーセットかもしれませんlock_guardが、その事実は両刃の剣です。型が行わないことが同じくらい重要な場合があります(この場合、デフォルトの構成)。


13

以下は、C ++の同時実行性のサンプルと引用です

friend void swap(X& lhs, X& rhs)
{
    if (&lhs == & rhs)
        return;
    std::lock(lhs.m, rhs.m);
    std::lock_guard<std::mutex> lock_a(lhs.m, std::adopt_lock);
    std::lock_guard<std::mutex> lock_b(rhs.m, std::adopt_lock);
    swap(lhs.some_detail, rhs.some_detail);
}

friend void swap(X& lhs, X& rhs)
{
    if (&lhs == &rhs)
        return;
    std::scoped_lock guard(lhs.m, rhs.m);
    swap(lhs.some_detail, rhs.some_detail);
}

が存在std::scoped_lockするということは、std::lockc ++ 17より前に使用していたほとんどのケースがを使用して記述できるようになりstd::scoped_lock、間違いの可能性が少なくなるということです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.