namespace std {
template <class... MutexTypes>
class scoped_lock;
}
概要
scoped_lock
は、複数のミューテックスに対するロック取得と解放を、コンストラクタとデストラクタで確実に実行するためのクラスである。
lock_guard
クラスは単一のミューテックスのみを扱うが、このクラスは複数のミューテックスを一括して管理する。
複数のミューテックスを使用する状況では、ロック取得の順番によってはデッドロックが発生する可能性がある:
// デッドロックが発生するコード:
// thread 1
{
std::lock_guard<std::mutex> lk1{m1};
std::lock_guard<std::mutex> lk2{m2};
}
// thread 2
{
std::lock_guard<std::mutex> lk1{m2}; // ロックの取得順に一貫性がない
std::lock_guard<std::mutex> lk2{m1};
}
このような状況では、従来はstd::lock()
関数によってロック取得を行い、ロック取得済みのミューテックスをstd::adopt_lock
戦略でロックの生存期間管理をすることでデッドロックを回避できた。このクラスでは、可変個のミューテックスをデッドロックを回避しながらロック取得と解放を安全に行える。
メンバ関数
名前 | 説明 | 対応バージョン |
---|---|---|
(constructor) |
コンストラクタ | C++17 |
(destructor) |
デストラクタ | C++17 |
operator=(const scoped_lock&) = delete |
代入演算子 | C++17 |
メンバ型
名前 | 説明 | 対応バージョン |
---|---|---|
mutex_type |
ミューテックス型。MutexTypes... が単一要素の場合のみ、その別名として定義される |
C++17 |
例
#include <iostream>
#include <mutex>
int main()
{
std::mutex m1;
std::timed_mutex m2;
{
// m1とm2のロックを取得
std::scoped_lock lk{m1, m2};
// m1のミューテックスで保護されたデータと、
// m2のミューテックスで保護されたデータを操作・・・
} // lkのデストラクタによって、m1とm2のロックを解放
}
18
#include <iostream>
#include <mutex>
int main()
{
std::mutex m1;
std::timed_mutex m2;
{
// m1とm2のロックを取得
std::scoped_lock lk{m1, m2};
// m1のミューテックスで保護されたデータと、
// m2のミューテックスで保護されたデータを操作・・・
} // lkのデストラクタによって、m1とm2のロックを解放
}
出力
バージョン
言語
- C++17
処理系
- Clang: 5.0 ✅
- GCC: 7.3 ✅
- Visual C++: ??