diff --git a/reference/rcu.md b/reference/rcu.md index a318cc408..1268415d3 100644 --- a/reference/rcu.md +++ b/reference/rcu.md @@ -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 | ## バージョン diff --git a/reference/rcu/rcu_barrier.md b/reference/rcu/rcu_barrier.md new file mode 100644 index 000000000..0d23366de --- /dev/null +++ b/reference/rcu/rcu_barrier.md @@ -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) diff --git a/reference/rcu/rcu_domain.md b/reference/rcu/rcu_domain.md index b3a6b5369..07e054918 100644 --- a/reference/rcu/rcu_domain.md +++ b/reference/rcu/rcu_domain.md @@ -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保護区間は入れ子になってもよい。 ## メンバ関数 @@ -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) diff --git a/reference/rcu/rcu_domain/unlock.md b/reference/rcu/rcu_domain/unlock.md index bd315492b..acbfa07a1 100644 --- a/reference/rcu/rcu_domain/unlock.md +++ b/reference/rcu/rcu_domain/unlock.md @@ -19,7 +19,7 @@ RCU機構により保護される共有データの読み取り終了を宣言 ## 効果 直近に開かれたRCU保護区間を閉じる。 -`*this`上でスケジュールされた再利用操作を呼び出す可能性がある。 +`*this`上でスケジュールされた回収操作を呼び出す可能性がある。 ## 戻り値 @@ -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) ## 参照 diff --git a/reference/rcu/rcu_obj_base.md b/reference/rcu/rcu_obj_base.md index 0e2bc9bce..c5b30d33c 100644 --- a/reference/rcu/rcu_obj_base.md +++ b/reference/rcu/rcu_obj_base.md @@ -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 | ## 例 @@ -64,7 +64,7 @@ void updater() Data *old_data = data.exchange(newdata); // 古いデータを読み取り中のスレッドがなくなったタイミングで - // データ領域の再利用(メモリ解放)を行うようスケジューリングする + // データ領域の回収(メモリ解放)を行うようスケジューリングする old_data->retire(); } diff --git a/reference/rcu/rcu_obj_base/retire.md b/reference/rcu/rcu_obj_base/retire.md index deadc7b28..8c04fcde7 100644 --- a/reference/rcu/rcu_obj_base/retire.md +++ b/reference/rcu/rcu_obj_base/retire.md @@ -13,7 +13,7 @@ void retire(D d = D(), * rcu_default_domain[link ../rcu_default_domain.md] ## 概要 -RCU機構により保護されるオブジェクト再利用をスケジュールする。 +RCU機構により保護されるオブジェクト回収をスケジュールする。 ## 適格要件 @@ -50,6 +50,7 @@ RCU機構により保護されるオブジェクト再利用をスケジュー ## 関連項目 - [`rcu_domain::unlock`](../rcu_domain/unlock.md) +- [`rcu_retire`](../rcu_retire.md) ## 参照 diff --git a/reference/rcu/rcu_retire.md b/reference/rcu/rcu_retire.md new file mode 100644 index 000000000..469ac230f --- /dev/null +++ b/reference/rcu/rcu_retire.md @@ -0,0 +1,125 @@ +# rcu_retire +* rcu[meta header] +* function template[meta id-type] +* std[meta namespace] +* cpp26[meta cpp] + +```cpp +namespace std{ + template> + 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)` == 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 +#include +#include +#include + +struct Data { + int m1, m2; +}; + +// 共有データを指すポインタ +std::atomic 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) diff --git a/reference/rcu/rcu_synchronize.md b/reference/rcu/rcu_synchronize.md new file mode 100644 index 000000000..b86626ada --- /dev/null +++ b/reference/rcu/rcu_synchronize.md @@ -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 +#include +#include +#include + +struct Data { + int m1, m2; +}; + +// 共有データを指すポインタ +std::atomic 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)