web-dev-qa-db-ja.com

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

C++ 17では、 std::scoped_lock という新しいロッククラスが導入されました。

ドキュメントから判断すると、既存のstd::lock_guardクラスに似ています。

違いは何ですか、いつ使用する必要がありますか?

85
inf

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

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

以前は、 this answer で説明したように、std::lockを使用して安全な方法で複数のミューテックスをロックするために少し踊らなければなりませんでした。

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

GCC 7は、すでにstd::scoped_lockをサポートしています。これは here で確認できます。

詳細については、 標準論文 をお読みください。

50
inf

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

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

74
Kerrek SB

以下はC++ Concurrency in Actionのサンプルと引用です:

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);
}

vs.

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が存在するということは、c ++ 17より前にstd::lockを使用していた場合のほとんどが、std::scoped_lockを使用して記述できるようになり、ミスの可能性が低くなります。

2
陳 力