std::shared_mutex
提供: cppreference.com
<tbody>
</tbody>
| ヘッダ <shared_mutex> で定義
|
||
class shared_mutex; |
(C++17以上) | |
shared_mutex クラスは複数のスレッドによる同時アクセスから共有データを保護するために使用できる同期プリミティブです。 排他アクセスを提供する他のミューテックス型と比べて、 shared_mutex は2レベルのアクセスを持ちます。
- 共有 - 複数のスレッドが同じミューテックスの所有権を共有できます。
- 排他 - 1つのスレッドだけがミューテックスを所有できます。
いずれかのスレッドが (lock または try_lock を通して) 排他ロックを取得している場合、他のスレッドはロック (共有も含みます) を取得できません。
いずれかのスレッドが (lock_shared または try_lock_shared を通して) 共有ロックを取得している場合、他のスレッドは排他ロックを取得できませんが、共有ロックは取得できます。
いずれのスレッドも排他ロックを取得していないときにのみ、共有ロックを取得できます。
ひとつのスレッドは同時にひとつ (共有または排他のいずれか) のロックしか取得できません。
shared_mutex は、共有データを任意個のスレッドから安全に並行的に読み込むことができけれども同時に読み書きしているスレッドが他にないときにのみ書き込むことができるときに、特に役に立ちます。
shared_mutex クラスは SharedMutex および StandardLayoutType の要件をすべて満たします。
メンバ型
| メンバ型 | 定義 |
native_handle_type(オプション)
|
処理系定義 |
メンバ関数
| ミューテックスを構築します (パブリックメンバ関数) | |
| ミューテックスを破棄します (パブリックメンバ関数) | |
operator= [削除] |
コピー代入可能ではありません (パブリックメンバ関数) |
排他ロック | |
| ミューテックスをロックします。 利用可能でない場合はブロックします (パブリックメンバ関数) | |
| ミューテックスのロックを試みます。 利用可能でない場合はリターンします (パブリックメンバ関数) | |
| ミューテックスのロックを解除します (パブリックメンバ関数) | |
共有ロック | |
| 共有所有権のためにミューテックスをロックします。 利用可能でない場合はブロックします (パブリックメンバ関数) | |
| 共有所有権のためにミューテックスのロックを試みます。 利用可能でない場合はリターンします (パブリックメンバ関数) | |
| ミューテックスの共有所有権のロックを解除します (パブリックメンバ関数) | |
ネイティブハンドル | |
| 処理系定義のベースとなるネイティブハンドルオブジェクトを返します (パブリックメンバ関数) | |
例
Run this code
#include <iostream>
#include <mutex> // std::unique_lock のため
#include <shared_mutex>
#include <thread>
class ThreadSafeCounter {
public:
ThreadSafeCounter() = default;
// 複数のスレッド/リーダが同時にカウンタの値を読み込むことができます。
unsigned int get() const {
std::shared_lock lock(mutex_);
return value_;
}
// 1つのスレッド/ライタのみがカウンタの値をインクリメント/書き込むことができます。
void increment() {
std::unique_lock lock(mutex_);
value_++;
}
// 1つのスレッド/ライタのみがカウンタの値をリセット/書き込むことができます。
void reset() {
std::unique_lock lock(mutex_);
value_ = 0;
}
private:
mutable std::shared_mutex mutex_;
unsigned int value_ = 0;
};
int main() {
ThreadSafeCounter counter;
auto increment_and_print = [&counter]() {
for (int i = 0; i < 3; i++) {
counter.increment();
std::cout << std::this_thread::get_id() << ' ' << counter.get() << '\n';
// 注意: 実際には std::cout への書き込みは別の std::mutex によって同様に同期する必要があります。
// ここでは例を小さく保つために省略しています。
}
};
std::thread thread1(increment_and_print);
std::thread thread2(increment_and_print);
thread1.join();
thread2.join();
}
// 説明: 以下の出力はシングルコアマシン上で生成されたものです。 スレッド1が開始すると、
// ループの1回目に入って increment() と get() を呼びます。しかし、その戻り値を
// std::cout に表示する前に、スケジューラがスレッド1をスリープ状態に起き、スレッド2を
// 起床させます。 スレッド2にはループの繰り返し3回を一気に実行する時間が十分にありました。
// まだループの1回目にいるスレッド1に戻り、最終的にそのカウンタの値のローカルコピー
// すなわち 1 を std::cout に表示し、ループの残り2回の繰り返しを実行します。
// マルチコアマシンでは、スリープ状態に置かれるスレッドはなく、出力が昇順になる可能性が
// 高くなります。
出力例:
123084176803584 2
123084176803584 3
123084176803584 4
123084185655040 1
123084185655040 5
123084185655040 6
関連項目
(C++14) |
タイムアウト付きのロックを実装する共有可能な相互排他機能を提供します (クラス) |