- mutex[meta header]
- std[meta namespace]
- function template[meta id-type]
- cpp11[meta cpp]
namespace std {
template <class L1, class L2, class... L3>
void lock(L1&, L2&, L3&...);
}
複数のミューテックスオブジェクトに対してlock操作を行う
テンプレートパラメータの型がlock()
、unlock()
、try_lock()
メンバ関数をサポートしていること
各ミューテックスオブジェクトに対して、lock()
、try_lock()
、あるいはunlock()
メンバ関数を順次呼び出すことで、デッドロックを引き起こさずに全ミューテックスをロックする。
いずれかのlock()
/try_lock()
が例外を送出した場合、以降のlock()
/try_lock()
呼び出しを行わず、それより前にロック取得したミューテックスオブジェクトに対してunlock()
メンバ関数を呼び出す。
なし
#include <iostream>
#include <cassert>
#include <mutex>
int main()
{
std::mutex mtx1;
std::recursive_mutex mtx2;
// 複数のミューテックスオブジェクトのロック取得を行う
{
std::lock(mtx1, mtx2);
mtx1.unlock();
mtx2.unlock();
}
// unique_lockに対してロック取得を行う
{
std::unique_lock<std::mutex> lk1(mtx1, std::defer_lock);
std::unique_lock<std::recursive_mutex> lk2(mtx2, std::defer_lock);
std::lock(lk1, lk2);
}
// 一部のlock()が失敗する場合
{
std::unique_lock<std::mutex> lk1(mtx1, std::defer_lock);
std::unique_lock<std::recursive_mutex> lk2(mtx2, std::defer_lock);
lk2.lock(); // ロック取得済みにしてlock()に渡す
try {
std::lock(lk1, lk2);
}
catch (std::system_error& e) {
std::cout << e.what() << std::endl;
}
// lk2が失敗したので、std::lock()内でlk2より前にロック取得が
// 成功した全てのミューテックスオブジェクトがunlock()される
assert(!lk1.owns_lock());
// lk2はロック取得済みで渡したので、ロック取得済み状態のまま
assert(lk2.owns_lock());
}
}
- std::lock[color ff0000]
- std::recursive_mutex[link recursive_mutex.md]
- mtx1.unlock()[link mutex/unlock.md]
- mtx2.unlock()[link mutex/unlock.md]
- std::defer_lock[link defer_lock.md]
- std::unique_lock[link unique_lock.md]
- lk2.lock()[link unique_lock/lock.md]
- std::system_error[link /reference/system_error/system_error.md]
- owns_lock()[link unique_lock/owns_lock.md]
Resource deadlock avoided
Visual C++ 11.0, 12.0では、このコードは正常に動作せず、1件目のassert
で動作を停止してしまう。unique_lock::lock()
のバグのためである。
- C++11
- Clang: ??
- GCC: 4.7.0 [mark verified]
- ICC: ??
- Visual C++: 2012 [mark verified], 2013 [mark verified], 2015 [mark verified]