std::lock
From cppreference.com
| ヘッダ <mutex> で定義 |
||
| template< class Lockable1, class Lockable2, class... LockableN > void lock( Lockable1& lock1, Lockable2& lock2, LockableN&... lockn ); |
(C++11以降) | |
与えられたLockableオブジェクト lock1, lock2, ..., lockn を、デッドロックを回避するアルゴリズムを使用してロックします。
オブジェクトは、`lock`、`try_lock`、`unlock` の未指定の系列の呼び出しによってロックされます。`lock` または `unlock` の呼び出しが例外を発生させた場合、例外を再スローする前に、ロックされたすべてのオブジェクトに対して `unlock` が呼び出されます。
目次 |
[編集] パラメータ
| lock1, lock2, ... , lockn | - | ロックする Lockable オブジェクト |
[編集] 戻り値
(なし)
[編集] 注
Boost は、イテレータのペアによって定義される Lockable オブジェクトのシーケンスを受け取るこの関数のバージョンを提供しています。
std::scoped_lock は、この関数の RAII ラッパーを提供し、`std::lock` の直接呼び出しよりも一般的に推奨されます。
[編集] 例
以下の例では、`std::lock` を使用して、デッドロックなしでミューテックスのペアをロックします。
このコードを実行
#include <chrono> #include <functional> #include <iostream> #include <mutex> #include <string> #include <thread> #include <vector> struct Employee { Employee(std::string id) : id(id) {} std::string id; std::vector<std::string> lunch_partners; std::mutex m; std::string output() const { std::string ret = "Employee " + id + " has lunch partners: "; for (auto n{lunch_partners.size()}; const auto& partner : lunch_partners) ret += partner + (--n ? ", " : ""); return ret; } }; void send_mail(Employee&, Employee&) { // Simulate a time-consuming messaging operation std::this_thread::sleep_for(std::chrono::milliseconds(696)); } void assign_lunch_partner(Employee& e1, Employee& e2) { static std::mutex io_mutex; { std::lock_guard<std::mutex> lk(io_mutex); std::cout << e1.id << " and " << e2.id << " are waiting for locks" << std::endl; } // Use std::lock to acquire two locks without worrying about // other calls to assign_lunch_partner deadlocking us { std::lock(e1.m, e2.m); std::lock_guard<std::mutex> lk1(e1.m, std::adopt_lock); std::lock_guard<std::mutex> lk2(e2.m, std::adopt_lock); // Equivalent code (if unique_locks are needed, e.g. for condition variables) // std::unique_lock<std::mutex> lk1(e1.m, std::defer_lock); // std::unique_lock<std::mutex> lk2(e2.m, std::defer_lock); // std::lock(lk1, lk2); // Superior solution available in C++17 // std::scoped_lock lk(e1.m, e2.m); { std::lock_guard<std::mutex> lk(io_mutex); std::cout << e1.id << " and " << e2.id << " got locks" << std::endl; } e1.lunch_partners.push_back(e2.id); e2.lunch_partners.push_back(e1.id); } send_mail(e1, e2); send_mail(e2, e1); } int main() { Employee alice("Alice"), bob("Bob"), christina("Christina"), dave("Dave"); // Assign in parallel threads because mailing users about lunch assignments // takes a long time std::vector<std::thread> threads; threads.emplace_back(assign_lunch_partner, std::ref(alice), std::ref(bob)); threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(bob)); threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(alice)); threads.emplace_back(assign_lunch_partner, std::ref(dave), std::ref(bob)); for (auto& thread : threads) thread.join(); std::cout << alice.output() << '\n' << bob.output() << '\n' << christina.output() << '\n' << dave.output() << '\n'; }
実行結果の例
Alice and Bob are waiting for locks Alice and Bob got locks Christina and Bob are waiting for locks Christina and Bob got locks Christina and Alice are waiting for locks Dave and Bob are waiting for locks Dave and Bob got locks Christina and Alice got locks Employee Alice has lunch partners: Bob, Christina Employee Bob has lunch partners: Alice, Christina, Dave Employee Christina has lunch partners: Bob, Alice Employee Dave has lunch partners: Bob
[編集] 関連項目
| (C++11) |
ムーブ可能なミューテックス所有権ラッパーを実装する (クラステンプレート) |
| (C++11) |
try_lockの繰り返し呼び出しによってミューテックスの所有権を取得しようと試みる(関数テンプレート) |
| (C++17) |
デッドロックを回避する、複数のミューテックス用のRAIIラッパー (クラステンプレート) |