std:: scoped_lock
|
ヘッダーで定義
<mutex>
|
||
|
template
<
class
...
MutexTypes
>
class scoped_lock ; |
(C++17以降) | |
scoped_lock
クラスは、スコープブロックの期間中に0個以上のミューテックスを所有するための便利な
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 member function) |
|
scoped_lock
オブジェクトを破棄し、基盤となるミューテックスのロックを解除する
(public member function) |
|
|
operator=
[deleted]
|
コピー代入不可
(public member function) |
注記
初心者がよく犯すエラーは、
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 <syncstream>
#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 = "従業員 " + id + " はランチパートナーを持っています: ";
for (int count{}; const auto& partner : lunch_partners)
ret += (count++ ? ", " : "") + partner;
return ret;
}
};
void send_mail(Employee&, Employee&)
{
// 時間のかかるメッセージング操作をシミュレート
std::this_thread::sleep_for
(注:元のテキストはC++の標準ライブラリ関数名であり、HTMLタグや属性も含まれていないため、翻訳対象となる自然言語のテキストが存在しません。C++の専門用語は翻訳しないという指示に従い、そのまま出力しています)(1s);
}
void assign_lunch_partner(Employee& e1, Employee& e2)
{
std::osyncstream
(注:指定された条件により、HTMLタグ・属性は翻訳せず、タグ内のテキストも翻訳対象外のため、元の形式を保持したまま出力しています) synced_out(std::cout);
synced_out << e1.id << " および " << e2.id << " はロックを待機中" << std::endl
(注:元のテキストはC++の標準ライブラリ要素を指しており、翻訳対象外のため、HTMLタグを保持したまま出力しています);
{
// std::scoped_lockを使用して、二つのロックを取得し、デッドロックの心配をせずに
// assign_lunch_partnerへの他の呼び出しがデッドロックを引き起こしている
// また、便利なRAIIスタイルのメカニズムも提供します
std::scoped_lock lock(e1.m, e2.m);
// 同等のコード 1 (std::lock と 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);
// 同等のコード 2 (unique_lockが必要な場合、例: 条件変数用)
// 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);
synced_out << e1.id << " および " << e2.id << " ロックを取得しました" << std::endl
(注:元のテキスト「std::endl」はC++固有の用語であり、HTMLタグ内に含まれているため、翻訳対象外としました。表示上は変更ありませんが、必要に応じて説明文を追加しています);
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("ボブ"), christina("クリスティーナ"), dave("Dave");
// ランチ割り当てについてユーザーにメール送信するため、並列スレッドで割り当てる
// 長時間を要する
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::osyncstream
(注:指定された条件により、HTMLタグ・属性は翻訳せず、C++固有の用語も翻訳していません。表示されるテキスト「std::osyncstream」はC++標準ライブラリのクラス名であるため、原文のまま保持しています)(std::cout) << alice.partners() << '\n'
<< bob.partners() << '\n'
<< christina.partners() << '\n'
<< dave.partners() << '\n';
}
出力例:
アリスとボブはロックを待っています アリスとボブはロックを取得しました クリスティーナとボブはロックを待っています クリスティーナとアリスはロックを待っています デイブとボブはロックを待っています デイブとボブはロックを取得しました クリスティーナとアリスはロックを取得しました クリスティーナとボブはロックを取得しました 従業員アリスのランチパートナー: ボブ、クリスティーナ 従業員ボブのランチパートナー: アリス、デイブ、クリスティーナ 従業員クリスティーナのランチパートナー: アリス、ボブ 従業員デイブのランチパートナー: ボブ
不具合報告
以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。
| DR | 適用対象 | 公開時の動作 | 正しい動作 |
|---|---|---|---|
| LWG 2981 | C++17 |
scoped_lock<MutexTypes...>
からの冗長なdeduction guideが提供されていた
|
削除 |
関連項目
|
(C++11)
|
移動可能なミューテックス所有権ラッパーを実装する
(クラステンプレート) |
|
(C++11)
|
厳密なスコープベースのミューテックス所有権ラッパーを実装する
(クラステンプレート) |