std::scoped_lock
From cppreference.com
| ヘッダ <mutex> で定義 |
||
| template< class... MutexTypes > class scoped_lock; |
(C++17以降) | |
クラスscoped_lockは、スコープブロックの期間中、ゼロ個以上のミューテックスを所有するための便利なRAIIスタイルのメカニズムを提供するミューテックスラッパーです。
scoped_lockオブジェクトが作成されると、与えられたミューテックスの所有権を取得しようとします。scoped_lockオブジェクトが作成されたスコープから制御が離れると、scoped_lockは破棄され、ミューテックスは解放されます。複数のミューテックスが与えられた場合、std::lockと同様にデッドロック回避アルゴリズムが使用されます。
scoped_lockクラスはコピーできません。
目次 |
[編集] テンプレートパラメータ
| MutexTypes | - | ロックするミューテックスの型。型はLockable要件を満たす必要があります。sizeof...(MutexTypes) == 1の場合を除き、その場合、唯一の型はBasicLockableを満たす必要があります。 |
[編集] メンバ型
| メンバ型 | 定義 |
mutex_type(条件付きで存在) |
sizeof...(MutexTypes) == 1の場合、メンバ型 |
[編集] メンバ関数
scoped_lockを構築し、オプションで指定されたミューテックスをロックする(public メンバ関数) | |
scoped_lockオブジェクトを破棄し、基になるミューテックスをアンロックする(public メンバ関数) | |
| operator= [削除] |
コピー代入不可 (public メンバ関数) |
[編集] 注釈
初心者がよく犯す間違いは、scoped_lock変数に名前を「つけ忘れる」ことです。例えば、std::scoped_lock(mtx);(これはmtxという名前のscoped_lock変数をデフォルト構築します)やstd::scoped_lock{mtx};(これは直ちに破棄されるprvalueオブジェクトを構築します)のように記述してしまい、結果的にスコープの残りの期間ミューテックスを保持するロックを実際に構築しないことになります。
| 機能テストマクロ | 値 | 規格 | 機能 |
|---|---|---|---|
__cpp_lib_scoped_lock |
201703L |
(C++17) | std::scoped_lock
|
[編集] 例
以下の例では、std::scoped_lockを使用してデッドロックなしでミューテックスのペアをロックし、RAIIスタイルを採用しています。
このコードを実行
#include <chrono> #include <functional> #include <iostream> #include <mutex> #include <string> #include <thread> #include <vector> using namespace std::chrono_literals; struct Employee { std::vector<std::string> lunch_partners; std::string id; std::mutex m; Employee(std::string id) : id(id) {} std::string partners() const { std::string ret = "Employee " + id + " has lunch partners: "; for (int count{}; const auto& partner : lunch_partners) ret += (count++ ? ", " : "") + partner; return ret; } }; void send_mail(Employee&, Employee&) { // Simulate a time-consuming messaging operation std::this_thread::sleep_for(1s); } 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::scoped_lock to acquire two locks without worrying about // other calls to assign_lunch_partner deadlocking us // and it also provides a convenient RAII-style mechanism std::scoped_lock lock(e1.m, e2.m); // Equivalent code 1 (using std::lock and std::lock_guard) // 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 2 (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); { 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.partners() << '\n' << bob.partners() << '\n' << christina.partners() << '\n' << dave.partners() << '\n'; }
実行結果の例
Alice and Bob are waiting for locks Alice and Bob got locks Christina and Bob are waiting for 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 Christina and Bob got locks Employee Alice has lunch partners: Bob, Christina Employee Bob has lunch partners: Alice, Dave, Christina Employee Christina has lunch partners: Alice, Bob Employee Dave has lunch partners: Bob
[編集] 欠陥報告
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| LWG 2981 | C++17 | scoped_lock<MutexTypes...>からの冗長な推論ガイドが提供されていた |
削除 |
[編集] 関連項目
| (C++11) |
ムーブ可能なミューテックス所有権ラッパーを実装する (クラステンプレート) |
| (C++11) |
厳密なスコープベースのミューテックス所有権ラッパーを実装する (クラステンプレート) |