Skip to content

Commit

Permalink
rcu: 非メンバ関数群 (#1183)
Browse files Browse the repository at this point in the history
  • Loading branch information
yohhoy committed Feb 5, 2025
1 parent eda1e0c commit 9a152c2
Show file tree
Hide file tree
Showing 8 changed files with 310 additions and 11 deletions.
6 changes: 3 additions & 3 deletions reference/rcu.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ RCU同期メカニズムは、複数スレッド間で共有されるデータ
| [`rcu_obj_base`](rcu/rcu_obj_base.md) | RCU対象オブジェクトの基底クラス(class template) | C++26 |
| [`rcu_domain`](rcu/rcu_domain.md) | RCUドメイン(class) | C++26 |
| [`rcu_default_domain`](rcu/rcu_default_domain.md) | デフォルトのRCUドメイン取得(function) | C++26 |
| [`rcu_synchronize`](rcu/rcu_synchronize.md.nolink) | RCUドメインのアンロック完了を待機(function) | C++26 |
| [`rcu_barrier`](rcu/rcu_barrier.md.nolink) | メモリ解放操作完了を待機(function) | C++26 |
| [`rcu_retire`](rcu/rcu_barrier.md.nolink) | メモリ解放操作をスケジュル(function template) | C++26 |
| [`rcu_synchronize`](rcu/rcu_synchronize.md) | RCUドメインのアンロック完了を待機(function) | C++26 |
| [`rcu_barrier`](rcu/rcu_barrier.md) | メモリ回収操作完了を待機(function) | C++26 |
| [`rcu_retire`](rcu/rcu_retire.md) | メモリ回収操作をスケジュール(function template) | C++26 |


## バージョン
Expand Down
57 changes: 57 additions & 0 deletions reference/rcu/rcu_barrier.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# rcu_barrier
* rcu[meta header]
* function[meta id-type]
* std[meta namespace]
* cpp26[meta cpp]

```cpp
namespace std {
void rcu_barrier(rcu_domain& dom = rcu_default_domain()) noexcept;
}
```
* rcu_domain[link rcu_domain.md]
* rcu_default_domain[link rcu_default_domain.md]
## 概要
スケジュールされたメモリ回収操作の完了を待機する。
## 効果
RCUドメイン`dom`上でスケジュールされた回収操作を評価する可能性がある。
`rcu_barrier`呼び出しよりも前に発生する評価で、かつ`dom`上での操作`E`をスケジュールする評価については、`E`が評価されるまでブロックする。
## 同期操作
`E`のあらゆる評価は、`rcu_barrier`からの戻りよりも確実に前に発生する。
## 戻り値
なし
## 例外
投げない
## 備考
`rcu_barrier`呼び出しは、暗黙に[`rcu_synchronize`](rcu_synchronize.md)を呼ばない。
## バージョン
### 言語
- C++26
### 処理系
- [Clang](/implementation.md#clang): ??
- [GCC](/implementation.md#gcc): ??
- [ICC](/implementation.md#icc): ??
- [Visual C++](/implementation.md#visual_cpp): ??
## 関連項目
- [`rcu_retire`](rcu_retire.md)
- [`rcu_obj_base::retire`](rcu_obj_base/retire.md)
## 参照
- [P2545R4 Read-Copy Update(RCU)](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2545r4.pdf)
4 changes: 2 additions & 2 deletions reference/rcu/rcu_domain.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace std {
RCU同期メカニズムで保護する共有データに対応付ける、RCUドメインを表現する。
`rcu_domain`クラスは Cpp17Lockable 要件を満たし、共有データの読み取りをおこなうRCU保護区間を表現する。
RCU保護区間は`lock`呼び出しから`unlock()`呼び出しのまでの区間であり、RCUドメインに対して同一スレッド上でのRCU保護区間は入れ子になってもよい。
RCU保護区間は[`lock`](rcu_domain/lock.md)呼び出しから[`unlock`](rcu_domain/unlock.md)呼び出しのまでの区間であり、RCUドメインに対して同一スレッド上でのRCU保護区間は入れ子になってもよい。
## メンバ関数
Expand Down Expand Up @@ -67,7 +67,7 @@ int main()

## 関連項目
- [`rcu_default_domain`](rcu_default_domain.md)
- [`rcu_retire`](rcu_retire.md.nolink)
- [`rcu_retire`](rcu_retire.md)
- [`rcu_obj_base::retire`](rcu_obj_base/retire.md)


Expand Down
6 changes: 3 additions & 3 deletions reference/rcu/rcu_domain/unlock.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ RCU機構により保護される共有データの読み取り終了を宣言

## 効果
直近に開かれたRCU保護区間を閉じる。
`*this`上でスケジュールされた再利用操作を呼び出す可能性がある
`*this`上でスケジュールされた回収操作を呼び出す可能性がある


## 戻り値
Expand All @@ -43,8 +43,8 @@ RCU機構により保護される共有データの読み取り終了を宣言

## 関連項目
- [`lock`](lock.md)
- [`rcu_retire`](../rcu_retire.md.nolink)
- [`rcu_obj_base::retire`](../rcu_rcu_obj_base/retire.md.nolink)
- [`rcu_retire`](../rcu_retire.md)
- [`rcu_obj_base::retire`](../rcu_obj_base/retire.md)


## 参照
Expand Down
4 changes: 2 additions & 2 deletions reference/rcu/rcu_obj_base.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ RCU機構の保護対象とする型の基底クラス。
| [`(constructor)`](rcu_obj_base/op_constructor.md) | コンストラクタ | C++26 |
| `(destructor)` | デストラクタ | C++26 |
| [`operator=`](rcu_obj_base/op_assign.md) | 代入演算子 | C++26 |
| [`retire`](rcu_obj_base/retire.md) | オブジェクト再利用をスケジュールする | C++26 |
| [`retire`](rcu_obj_base/retire.md) | オブジェクト回収をスケジュールする | C++26 |
## 例
Expand Down Expand Up @@ -64,7 +64,7 @@ void updater()
Data *old_data = data.exchange(newdata);
// 古いデータを読み取り中のスレッドがなくなったタイミングで
// データ領域の再利用(メモリ解放)を行うようスケジューリングする
// データ領域の回収(メモリ解放)を行うようスケジューリングする
old_data->retire();
}
Expand Down
3 changes: 2 additions & 1 deletion reference/rcu/rcu_obj_base/retire.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ void retire(D d = D(),
* rcu_default_domain[link ../rcu_default_domain.md]
## 概要
RCU機構により保護されるオブジェクト再利用をスケジュールする
RCU機構により保護されるオブジェクト回収をスケジュールする
## 適格要件
Expand Down Expand Up @@ -50,6 +50,7 @@ RCU機構により保護されるオブジェクト再利用をスケジュー
## 関連項目
- [`rcu_domain::unlock`](../rcu_domain/unlock.md)
- [`rcu_retire`](../rcu_retire.md)
## 参照
Expand Down
125 changes: 125 additions & 0 deletions reference/rcu/rcu_retire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# rcu_retire
* rcu[meta header]
* function template[meta id-type]
* std[meta namespace]
* cpp26[meta cpp]

```cpp
namespace std{
template<class T, class D = default_delete<T>>
void rcu_retire(T* p,
D d = D(),
rcu_domain& dom = rcu_default_domain());
}
```
* default_delete[link /reference/memory/default_delete.md]
* rcu_domain[link rcu_domain.md]
* rcu_default_domain[link rcu_default_domain.md]

## 概要
RCU機構により保護されるオブジェクト回収をスケジュールする。


## 適格要件
[`is_move_constructible_v`](/reference/type_traits/is_move_constructible.md)`<D> == true`、かつ式`d(p)`が妥当であること。


## 事前条件
`D`はCpp17MoveCosntructible要件およびCpp17Destructible要件をみたすこと。


## 効果
- メモリを確保する可能性がある。
- メモリ確保が`operator new`を呼び出すか否かは未規定である。
- `D`型のオブジェクト`d1``std::move(d)`で初期化する。
- RCUドメイン`dom`に対して式`d1(p)`の評価をスケジュールする。
- 評価が例外で終了した場合は未定義の動作を引き起こす。
- `dom`に対してスケジュールされた評価を呼び出す可能性がある。


## 戻り値
なし


## 例外
[`bad_alloc`](/reference/new/bad_alloc.md)、または`d1`初期化中に送出された例外。


##
```cpp example
#include <atomic>
#include <mutex>
#include <thread>
#include <rcu>

struct Data {
int m1, m2;
};

// 共有データを指すポインタ
std::atomic<Data*> data;

void reader()
{
std::scoped_lock slk{std::rcu_default_domain()};
// 共有データを読み取り(Read)
Data *p = data;

std::println("{} {}", p->m1, p->m2);
}

void updater()
{
Data *newdata = new Data{1, 2};
// 新しいデータで共有データを更新(Update)
Data *old_data = data.exchange(newdata);

// 古いデータを読み取り中のスレッドがなくなったタイミングで
// データ領域の回収(メモリ解放)を行うようスケジューリングする
std::rcu_retire(old_data);
}

int main()
{
// 共有データ初期化
Data *newdata = new Data{0, 0};
data.store(newdata);

// 共有データへ並行アクセス
std::jthread th{[] {
for (int i = 0; i < 3; i++) {
reader();
}
}};
updater();
}
```
* std::rcu_retire[color ff0000]
* std::rcu_default_domain[link rcu_default_domain.md]
* std::scoped_lock[link /reference/mutex/scoped_lock.md]
### 出力例
```
0 0
1 2
1 2
```
## バージョン
### 言語
- C++26
### 処理系
- [Clang](/implementation.md#clang): ??
- [GCC](/implementation.md#gcc): ??
- [ICC](/implementation.md#icc): ??
- [Visual C++](/implementation.md#visual_cpp): ??
## 関連項目
- [`rcu_domain::unlock`](rcu_domain/unlock.md)
- [`rcu_obj_base::retire`](rcu_obj_base/retire.md)
## 参照
- [P2545R4 Read-Copy Update(RCU)](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2545r4.pdf)
116 changes: 116 additions & 0 deletions reference/rcu/rcu_synchronize.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# rcu_synchronize
* rcu[meta header]
* function[meta id-type]
* std[meta namespace]
* cpp26[meta cpp]

```cpp
namespace std {
void rcu_synchronize(rcu_domain& dom = rcu_default_domain()) noexcept;
}
```
* rcu_domain[link rcu_domain.md]
* rcu_default_domain[link rcu_default_domain.md]
## 概要
RCUドメインのアンロック完了を待機する。
## 効果
もし`rcu_synchronize`呼び出しが`dom`上のRCU保護区間`R`のロックを開く操作よりも確実に前に発生するのでなければ、`R`を閉じる[`unlock`](rcu_domain/unlock.md)まで現スレッドをブロックする。
## 同期操作
`R`を閉じる[`unlock`](rcu_domain/unlock.md)は、`rcu_synchronize`からの戻りよりも確実に前に発生する。
## 戻り値
なし
## 例外
投げない
## 備考
`rcu_synchronize`呼び出しは、暗黙に[`rcu_barrier`](rcu_barrier.md)を呼ばない。
## 例
```cpp example
#include <atomic>
#include <mutex>
#include <thread>
#include <rcu>
struct Data {
int m1, m2;
};
// 共有データを指すポインタ
std::atomic<Data*> data;
void reader()
{
std::scoped_lock slk{std::rcu_default_domain()};
// 共有データを読み取り(Read)
Data *p = data;
std::println("{} {}", p->m1, p->m2);
}
void updater()
{
Data *newdata = new Data{1, 2};
// 新しいデータで共有データを更新(Update)
Data *old_data = data.exchange(newdata);
// 古いデータを読み取り中のスレッドがなくるまで待機する
std::rcu_synchronize();
delete old_data;
}
int main()
{
// 共有データ初期化
Data *newdata = new Data{0, 0};
data.store(newdata);
// 共有データへ並行アクセス
std::jthread th{[] {
for (int i = 0; i < 3; i++) {
reader();
}
}};
updater();
}
```
* std::rcu_synchronize[color ff0000]
* std::rcu_default_domain[link rcu_default_domain.md]
* std::scoped_lock[link /reference/mutex/scoped_lock.md]

### 出力例
```
0 0
1 2
1 2
```


## バージョン
### 言語
- C++26

### 処理系
- [Clang](/implementation.md#clang): ??
- [GCC](/implementation.md#gcc): ??
- [ICC](/implementation.md#icc): ??
- [Visual C++](/implementation.md#visual_cpp): ??


## 関連項目
- [`rcu_domain`](rcu_domain.md)


## 参照
- [P2545R4 Read-Copy Update(RCU)](https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2545r4.pdf)

0 comments on commit 9a152c2

Please sign in to comment.