C++ 17では、 std::scoped_lock
という新しいロッククラスが導入されました。
ドキュメントから判断すると、既存のstd::lock_guard
クラスに似ています。
違いは何ですか、いつ使用する必要がありますか?
唯一の重要な違いは、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 で確認できます。
詳細については、 標準論文 をお読みください。
scoped_lock
は、lock_guard
の厳密に優れたバージョンであり、任意の数のミューテックスを一度にロックします(std::lock
と同じデッドロック回避アルゴリズムを使用)。新しいコードでは、scoped_lock
のみを使用する必要があります。
lock_guard
がまだ存在する唯一の理由は、互換性のためです。現在のコードで使用されているため、単に削除することはできませんでした。さらに、定義を(単項から可変)に変更することは望ましくないことがわかりました。
以下は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
を使用して記述できるようになり、ミスの可能性が低くなります。