diff --git a/GLOBAL_QUALIFY_LIST.txt b/GLOBAL_QUALIFY_LIST.txt index acc4efaa42..afbdbd2412 100644 --- a/GLOBAL_QUALIFY_LIST.txt +++ b/GLOBAL_QUALIFY_LIST.txt @@ -169,6 +169,7 @@ * identity[link /reference/functional/identity.md] * [link /reference/future.md] * [link /reference/generator.md] +* [link /reference/hazard_pointer.md] * [link /reference/hive.md] * [link /reference/initializer_list.md] * std::initializer_list[link /reference/initializer_list/initializer_list.md] diff --git a/lang/cpp26.md b/lang/cpp26.md index e7c612a45d..45b751a4a8 100644 --- a/lang/cpp26.md +++ b/lang/cpp26.md @@ -135,7 +135,7 @@ C++26とは、2026年中に改訂される予定の、C++バージョンの通 - 文字列エンコーディングを識別するライブラリとして、[``](/reference/text_encoding.md)を追加 - 要素のメモリ位置が安定するシーケンスコンテナのライブラリとして[``](/reference/hive.md)を追加 - 並行処理におけるデータの参照・更新を行うRCU (Read Copy Update) のライブラリとして、[``](/reference/rcu.md)を追加 -- 並行処理において参照中のデータが更新されないよう保護するハザードポインタのライブラリとして、[``](/reference/hazard_pointer.md.nolink)を追加 +- 並行処理において参照中のデータが更新されないよう保護するハザードポインタのライブラリとして、[``](/reference/hazard_pointer.md)を追加 - データ並列ライブラリとして、[``](/reference/simd.md)を追加 - デバッグサポートのライブラリとして[``](/reference/debugging.md)を追加 - 線形代数ライブラリとして[``](/reference/linalg.md)を追加 diff --git a/lang/cpp26/feature_test_macros.md b/lang/cpp26/feature_test_macros.md index c029b5848e..1235b82ec6 100755 --- a/lang/cpp26/feature_test_macros.md +++ b/lang/cpp26/feature_test_macros.md @@ -107,7 +107,7 @@ |`__cpp_lib_freestanding_variant`|`202311L`||[``](/reference/variant.md)| |`__cpp_lib_fstream_native_handle`|`202306L`|[`std::basic_fstream`](/reference/fstream/basic_fstream.md)などのメンバに、ファイルのネイティブハンドルを追加|[``](/reference/fstream.md)| |`__cpp_lib_function_ref`|`202604L`|[``](/reference/functional.md)に[`std::function_ref`](/reference/functional/function_ref.md)を追加|[``](/reference/functional.md)| -|`__cpp_lib_hazard_pointer`|`202306L`|ハザードポインタのライブラリ[``](/reference/hazard_pointer.md.nolink)を追加|[``](/reference/hazard_pointer.md.nolink)| +|`__cpp_lib_hazard_pointer`|`202306L`|ハザードポインタのライブラリ[``](/reference/hazard_pointer.md)を追加|[``](/reference/hazard_pointer.md)| |`__cpp_lib_hive`|`202502L`|シーケンスコンテナのライブラリ[``](/reference/hive.md)を追加|[``](/reference/hive.md)| |`__cpp_lib_indirect`|`202502L`|[``](/reference/memory.md)に[`std::indirect`](/reference/memory/indirect.md)と[`std::polymorphic`](/reference/memory/polymorphic.md)を追加|[``](/reference/memory.md)| |`__cpp_lib_inplace_vector`|`202603L`|容量固定の可変長配列のライブラリ[``](/reference/inplace_vector.md)を追加|[``](/reference/inplace_vector.md)| diff --git a/lang/cpp29.md b/lang/cpp29.md index ca2fdd6633..2593bd6d6b 100644 --- a/lang/cpp29.md +++ b/lang/cpp29.md @@ -116,6 +116,7 @@ C++29とは、2029年中に改訂される予定の、C++バージョンの通 - 指定したマスクで立っている一のビットを下位に詰める[`std::simd::bit_compress()`](/reference/simd/bit_compress.md)関数 - 下位ビットを指定したマスクが立っている位置へ展開する[`std::simd::bit_expand()`](/reference/simd/bit_expand.md)関数 - 未定義動作にならないビットシフト[`std::simd::shl()`](/reference/simd/shl.md)関数と[`std::simd::shr()`](/reference/simd/shr.md)関数 +- [``](/reference/hazard_pointer.md)に、複数のハザードポインタをまとめて構築・破棄する[`std::make_hazard_pointer_batch()`](/reference/hazard_pointer/make_hazard_pointer_batch.md)関数と[`std::clear_hazard_pointer_batch()`](/reference/hazard_pointer/clear_hazard_pointer_batch.md)関数を追加 ### 非推奨化 - [``](/reference/iostream.md)において、`signed char` / `unsigned char`の入出力を非推奨化。[`std::int8_t`](/reference/cstdint/int8_t.md) / [`std::uint8_t`](/reference/cstdint/uint8_t.md)の別名として扱われるこれらの型の入出力で、整数型であることを期待して予期せぬ結果を招く可能性があった diff --git a/lang/cpp29/feature_test_macros.md b/lang/cpp29/feature_test_macros.md index 1d05023bc1..6c1e4c3945 100644 --- a/lang/cpp29/feature_test_macros.md +++ b/lang/cpp29/feature_test_macros.md @@ -17,6 +17,7 @@ | マクロ名 | 値 | 機能 | ヘッダ | |----------|----|------|--------| +|`__cpp_lib_hazard_pointer`|`202606L`|[``](/reference/hazard_pointer.md)に、複数のハザードポインタをまとめて構築・破棄する[`std::make_hazard_pointer_batch()`](/reference/hazard_pointer/make_hazard_pointer_batch.md)関数と[`std::clear_hazard_pointer_batch()`](/reference/hazard_pointer/clear_hazard_pointer_batch.md)関数を追加|[``](/reference/hazard_pointer.md)| |`__cpp_lib_simd`|`202606L`|[``](/reference/simd.md)に、SIMDデータ用の連番を生成する[`std::simd::iota`](/reference/simd/iota.md)変数テンプレートなどを追加|[``](/reference/simd.md)| |`__cpp_lib_simd_bitops`|`202607L`|[``](/reference/simd.md)に、ビット列を操作する[`bit_reverse()`](/reference/simd/bit_reverse.md)・[`bit_repeat()`](/reference/simd/bit_repeat.md)・[`bit_compress()`](/reference/simd/bit_compress.md)・[`bit_expand()`](/reference/simd/bit_expand.md)関数と、未定義動作にならないシフト[`shl()`](/reference/simd/shl.md)・[`shr()`](/reference/simd/shr.md)関数を追加|[``](/reference/simd.md)| diff --git a/reference.md b/reference.md index d9c5f28471..b5aff4ad1e 100644 --- a/reference.md +++ b/reference.md @@ -213,7 +213,7 @@ | [``](/reference/barrier.md) | バリア同期 | C++20 | | [``](/reference/future.md) | Future | C++11 | | [``](/reference/rcu.md) | データの参照・更新 | C++26 | -| [``](/reference/hazard_pointer.md.nolink) | ハザードポインタ | C++26 | +| [``](/reference/hazard_pointer.md) | ハザードポインタ | C++26 | | [``](/reference/simd.md) | データ並列 | C++26 | diff --git a/reference/hazard_pointer.md b/reference/hazard_pointer.md new file mode 100644 index 0000000000..32c36938dc --- /dev/null +++ b/reference/hazard_pointer.md @@ -0,0 +1,45 @@ +# hazard_pointer +* hazard_pointer[meta header] +* cpp26[meta cpp] + +``ヘッダは、ハザードポインタ (hazard pointer) による安全な遅延回収 (safe deferred reclamation) の機能を提供する。 + +ハザードポインタは、複数スレッドから並行に参照される動的オブジェクトを、参照中に破棄されないよう保護するための仕組みである。ロックフリーなデータ構造で、あるスレッドがオブジェクトを参照している間、別のスレッドがそのオブジェクトを安全に回収 (reclaim) できるようにする。 + +- オブジェクトを保護する側のスレッドは、[`hazard_pointer`](hazard_pointer/hazard_pointer.md)オブジェクトを取得し、参照するオブジェクトを指すよう設定する(保護)。 +- オブジェクトを削除する側のスレッドは、削除したオブジェクトを[`retire()`](hazard_pointer/hazard_pointer_obj_base/retire.md)メンバ関数で回収予約する。予約されたオブジェクトは、どのハザードポインタからも指されていないことが確認された後に回収される(遅延回収)。 + +ハザードポインタで保護できるオブジェクトは、[`hazard_pointer_obj_base`](hazard_pointer/hazard_pointer_obj_base.md)を基底クラスとして継承する必要がある。 + + +## クラス + +| 名前 | 説明 | 対応バージョン | +|------|------|----------------| +| [`hazard_pointer_obj_base`](hazard_pointer/hazard_pointer_obj_base.md) | ハザードポインタで保護可能なオブジェクトの基底クラス (class template) | C++26 | +| [`hazard_pointer`](hazard_pointer/hazard_pointer.md) | ハザードポインタを所有するクラス (class) | C++26 | + + +## 関数 + +| 名前 | 説明 | 対応バージョン | +|------|------|----------------| +| [`make_hazard_pointer`](hazard_pointer/make_hazard_pointer.md) | ハザードポインタを構築する | C++26 | +| [`make_hazard_pointer_batch`](hazard_pointer/make_hazard_pointer_batch.md) | 複数のハザードポインタをまとめて構築する | C++29 | +| [`clear_hazard_pointer_batch`](hazard_pointer/clear_hazard_pointer_batch.md) | 複数のハザードポインタをまとめて破棄する | C++29 | + + +## バージョン +### 言語 +- C++26 + + +## 関連項目 +- [``](atomic.md) + + +## 参照 +- [P2530R3 Hazard Pointers for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2530r3.pdf) + - C++26で``ヘッダが追加された +- [P2422R1 Remove `nodiscard` annotations from the standard library specification](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2422r1.html) + - C++26で`[[nodiscard]]`指定が削除された diff --git a/reference/hazard_pointer/clear_hazard_pointer_batch.md b/reference/hazard_pointer/clear_hazard_pointer_batch.md new file mode 100644 index 0000000000..479d8f997f --- /dev/null +++ b/reference/hazard_pointer/clear_hazard_pointer_batch.md @@ -0,0 +1,102 @@ +# clear_hazard_pointer_batch +* hazard_pointer[meta header] +* std[meta namespace] +* function[meta id-type] +* cpp29[meta cpp] + +```cpp +namespace std { + void clear_hazard_pointer_batch(span batch) noexcept; // C++29 +} +``` +* span[link /reference/span/span.md] +* hazard_pointer[link hazard_pointer.md] + +## 概要 +複数のハザードポインタを、まとめて破棄する。 + +`batch`に含まれる非空の[`hazard_pointer`](hazard_pointer.md)オブジェクトそれぞれが所有するハザードポインタを破棄し、その要素を空にする。個別に破棄するよりも、複数のハザードポインタをまとめて破棄することでレイテンシを低減できる。 + +[`make_hazard_pointer_batch()`](make_hazard_pointer_batch.md)で構築したハザードポインタ群をまとめて破棄する用途に使用する。 + + +## 効果 +`batch`の各要素`e`について、`e.`[`empty()`](hazard_pointer/empty.md)が`false`であるものは、`e`が所有するハザードポインタを破棄し、`e`を空にする。 + +破棄されたハザードポインタが保護していたオブジェクトは、他に保護しているハザードポインタがなければ回収可能となる。 + + +## 戻り値 +なし + + +## 例外 +投げない + + +## 備考 +- 既に空の要素は変更されない。 + + +## 例 +```cpp example +#include +#include +#include +#include + +struct Data : std::hazard_pointer_obj_base { + int value; + explicit Data(int v) : value(v) {} +}; + +std::atomic data{new Data(42)}; + +int main() +{ + // ハザードポインタ群をまとめて構築する + std::array hp; + std::make_hazard_pointer_batch(hp); + + Data* p = hp[0].protect(data); + std::println("{}", p->value); + + // 使い終わったハザードポインタ群をまとめて破棄する + std::clear_hazard_pointer_batch(hp); + + // 後始末: 共有データを回収予約する + data.load()->retire(); +} +``` +* std::clear_hazard_pointer_batch[color ff0000] +* std::hazard_pointer_obj_base[link hazard_pointer_obj_base.md] +* std::make_hazard_pointer_batch[link make_hazard_pointer_batch.md] +* hp[0].protect[link hazard_pointer/protect.md] +* load[link /reference/atomic/atomic/load.md] +* retire()[link hazard_pointer_obj_base/retire.md] + +### 出力 +``` +42 +``` + + +## バージョン +### 言語 +- C++29 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 +- [`std::make_hazard_pointer_batch`](make_hazard_pointer_batch.md) +- [`std::hazard_pointer`](hazard_pointer.md) + + +## 参照 +- [P3428R4 Hazard Pointer Batches](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3428r4.pdf) + - C++29で追加された diff --git a/reference/hazard_pointer/hazard_pointer.md b/reference/hazard_pointer/hazard_pointer.md new file mode 100644 index 0000000000..8cf518009f --- /dev/null +++ b/reference/hazard_pointer/hazard_pointer.md @@ -0,0 +1,137 @@ +# hazard_pointer +* hazard_pointer[meta header] +* class[meta id-type] +* std[meta namespace] +* cpp26[meta cpp] + +```cpp +namespace std { + class hazard_pointer; +} +``` + +## 概要 +`hazard_pointer`は、1つのハザードポインタを所有するクラスである。 + +このクラスのオブジェクトは、「空 (empty)」であるか、ちょうど1つのハザードポインタを所有するかのいずれかである。ハザードポインタは同時に高々1つのスレッドから所有され、その所有スレッドだけが値を設定できる。ムーブのみ可能で、コピーはできない。 + +オブジェクトは通常、[`make_hazard_pointer()`](make_hazard_pointer.md)関数で構築する。参照したい共有オブジェクトを[`protect()`](hazard_pointer/protect.md)メンバ関数で保護すると、その保護が解除される (デストラクタや[`reset_protection()`](hazard_pointer/reset_protection.md)メンバ関数) まで、そのオブジェクトは[`retire()`](hazard_pointer_obj_base/retire.md)されても回収されない。 + +```cpp +std::hazard_pointer h = std::make_hazard_pointer(); +Data* p = h.protect(shared_ptr_atomic); // 保護開始 +// ... *p を安全に参照できる ... +// h のスコープ終了で保護終了 +``` + + +## メンバ関数 + +| 名前 | 説明 | 対応バージョン | +|------|------|----------------| +| [`(constructor)`](hazard_pointer/op_constructor.md) | コンストラクタ | C++26 | +| [`(destructor)`](hazard_pointer/op_destructor.md) | デストラクタ | C++26 | +| [`operator=`](hazard_pointer/op_assign.md) | ムーブ代入演算子 | C++26 | +| [`empty`](hazard_pointer/empty.md) | 空かどうかを判定する | C++26 | +| [`protect`](hazard_pointer/protect.md) | オブジェクトを保護する | C++26 | +| [`try_protect`](hazard_pointer/try_protect.md) | オブジェクトの保護を試みる | C++26 | +| [`reset_protection`](hazard_pointer/reset_protection.md) | 保護を解除する | C++26 | +| [`swap`](hazard_pointer/swap.md) | 他の`hazard_pointer`オブジェクトと入れ替える | C++26 | + + +## 非メンバ関数 + +| 名前 | 説明 | 対応バージョン | +|------|------|----------------| +| [`swap`](hazard_pointer/swap_free.md) | 2つの`hazard_pointer`オブジェクトを入れ替える | C++26 | +| [`make_hazard_pointer`](make_hazard_pointer.md) | ハザードポインタを構築する | C++26 | +| [`make_hazard_pointer_batch`](make_hazard_pointer_batch.md) | 複数のハザードポインタをまとめて構築する | C++29 | +| [`clear_hazard_pointer_batch`](clear_hazard_pointer_batch.md) | 複数のハザードポインタをまとめて破棄する | C++29 | + + +## 例 +```cpp example +#include +#include +#include +#include + +struct Data : std::hazard_pointer_obj_base { + int value; + explicit Data(int v) : value(v) {} +}; + +// 複数スレッドから並行にアクセスされる共有データ +std::atomic data{new Data(0)}; + +// 読み込み側スレッド +void reader() +{ + // ハザードポインタで共有データを保護してから参照する + std::hazard_pointer h = std::make_hazard_pointer(); + Data* p = h.protect(data); + + // 更新側スレッドが data を差し替えて retire しても、 + // このハザードポインタが保護している間は *p は回収されない + std::println("{}", p->value); +} // h のデストラクタで保護が解除される + +// 更新側スレッド +void updater() +{ + // 新しいデータで差し替え、取り外した古いデータを回収予約する + // (現役のオブジェクトは他スレッドが参照しうるので retire しない。 + // 差し替えて取り外したものだけを retire する) + Data* old = data.exchange(new Data(1)); + old->retire(); +} + +int main() +{ + // 読み込みスレッドと更新スレッドを並行に実行する + { + std::jthread r{reader}; + std::jthread w{updater}; + } // 両スレッドの終了を待つ + + // 最後に data が指しているオブジェクトも回収予約する + // (取り外したオブジェクトを retire し忘れると回収されずリークするので注意) + data.load()->retire(); +} +``` +* std::hazard_pointer[color ff0000] +* std::hazard_pointer_obj_base[link hazard_pointer_obj_base.md] +* std::make_hazard_pointer[link make_hazard_pointer.md] +* h.protect[link hazard_pointer/protect.md] +* old->retire()[link hazard_pointer_obj_base/retire.md] +* exchange[link /reference/atomic/atomic/exchange.md] +* data.load()[link /reference/atomic/atomic/load.md] +* std::jthread[link /reference/thread/jthread.md] + +### 出力例 +``` +0 +``` + + +## バージョン +### 言語 +- C++26 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 +- [`std::hazard_pointer_obj_base`](hazard_pointer_obj_base.md) +- [`std::make_hazard_pointer`](make_hazard_pointer.md) + + +## 参照 +- [P2530R3 Hazard Pointers for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2530r3.pdf) + - C++26で追加された +- [P2422R1 Remove `nodiscard` annotations from the standard library specification](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2422r1.html) + - C++26で`empty`メンバ関数の`[[nodiscard]]`指定が削除された diff --git a/reference/hazard_pointer/hazard_pointer/empty.md b/reference/hazard_pointer/hazard_pointer/empty.md new file mode 100644 index 0000000000..902f71558b --- /dev/null +++ b/reference/hazard_pointer/hazard_pointer/empty.md @@ -0,0 +1,42 @@ +# empty +* hazard_pointer[meta header] +* function[meta id-type] +* std[meta namespace] +* hazard_pointer[meta class] +* cpp26[meta cpp] + +```cpp +bool empty() const noexcept; +``` + +## 概要 +`*this`が空である(ハザードポインタを所有していない)かどうかを判定する。 + + +## 戻り値 +`*this`が空である場合にのみ`true`を返す。 + + +## 例外 +投げない + + +## 備考 +- 空の`hazard_pointer`オブジェクトは、非関連 (unassociated) 状態のハザードポインタを所有する`hazard_pointer`オブジェクトとは異なる。空のオブジェクトはハザードポインタを1つも所有していない。 + + +## バージョン +### 言語 +- C++26 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 参照 +- [P2530R3 Hazard Pointers for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2530r3.pdf) +- [P2422R1 Remove `nodiscard` annotations from the standard library specification](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2422r1.html) + - C++26で`[[nodiscard]]`指定が削除された diff --git a/reference/hazard_pointer/hazard_pointer/op_assign.md b/reference/hazard_pointer/hazard_pointer/op_assign.md new file mode 100644 index 0000000000..2f1a2bfc0e --- /dev/null +++ b/reference/hazard_pointer/hazard_pointer/op_assign.md @@ -0,0 +1,48 @@ +# operator= +* hazard_pointer[meta header] +* function[meta id-type] +* std[meta namespace] +* hazard_pointer[meta class] +* cpp26[meta cpp] + +```cpp +hazard_pointer& operator=(hazard_pointer&& other) noexcept; +``` + +## 概要 +ムーブ代入演算子。`other`が所有するハザードポインタを`*this`へ移動する。 + +コピー代入演算子は提供されない(ムーブ専用型である)。 + + +## 効果 +- `this == &other`が`true`の場合、何もしない。 +- そうでない場合、`*this`が空でなければ、`*this`が所有するハザードポインタを破棄し、その保護期間を終了する。 + + +## 事後条件 +- `other`が空だった場合、`*this`は空である。そうでない場合、`*this`は`other`がもともと所有していたハザードポインタを所有する。 +- `this != &other`が`true`の場合、`other`は空になる。 + + +## 戻り値 +`*this` + + +## 例外 +投げない + + +## バージョン +### 言語 +- C++26 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 参照 +- [P2530R3 Hazard Pointers for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2530r3.pdf) diff --git a/reference/hazard_pointer/hazard_pointer/op_constructor.md b/reference/hazard_pointer/hazard_pointer/op_constructor.md new file mode 100644 index 0000000000..984375e77d --- /dev/null +++ b/reference/hazard_pointer/hazard_pointer/op_constructor.md @@ -0,0 +1,45 @@ +# コンストラクタ +* hazard_pointer[meta header] +* function[meta id-type] +* std[meta namespace] +* hazard_pointer[meta class] +* cpp26[meta cpp] + +```cpp +hazard_pointer() noexcept; // (1) C++26 +hazard_pointer(hazard_pointer&& other) noexcept; // (2) C++26 +``` + +## 概要 +- (1): デフォルトコンストラクタ。空の`hazard_pointer`オブジェクトを構築する。 +- (2): ムーブコンストラクタ。 + +コピーコンストラクタは提供されない(ムーブ専用型である)。空でない`hazard_pointer`オブジェクトは、通常[`make_hazard_pointer()`](../make_hazard_pointer.md)関数で構築する。 + + +## 事後条件 +- (1): `*this`は空である。 +- (2): `other`が空だった場合、`*this`は空である。そうでない場合、`*this`は`other`がもともと所有していたハザードポインタを所有し、`other`は空になる。 + + +## 例外 +投げない + + +## バージョン +### 言語 +- C++26 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 +- [`std::make_hazard_pointer`](../make_hazard_pointer.md) + + +## 参照 +- [P2530R3 Hazard Pointers for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2530r3.pdf) diff --git a/reference/hazard_pointer/hazard_pointer/op_destructor.md b/reference/hazard_pointer/hazard_pointer/op_destructor.md new file mode 100644 index 0000000000..c1292b8ac9 --- /dev/null +++ b/reference/hazard_pointer/hazard_pointer/op_destructor.md @@ -0,0 +1,42 @@ +# デストラクタ +* hazard_pointer[meta header] +* function[meta id-type] +* std[meta namespace] +* hazard_pointer[meta class] +* cpp26[meta cpp] + +```cpp +~hazard_pointer(); +``` + +## 概要 +`hazard_pointer`オブジェクトを破棄する。 + + +## 効果 +`*this`が空でない場合、`*this`が所有するハザードポインタを破棄し、その保護期間 (protection epoch) を終了する。 + +これにより、このハザードポインタで保護していたオブジェクトは、他に保護しているハザードポインタがなければ回収可能となる。 + + +## 例外 +投げない + + +## バージョン +### 言語 +- C++26 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 +- [`std::hazard_pointer::reset_protection`](reset_protection.md) + + +## 参照 +- [P2530R3 Hazard Pointers for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2530r3.pdf) diff --git a/reference/hazard_pointer/hazard_pointer/protect.md b/reference/hazard_pointer/hazard_pointer/protect.md new file mode 100644 index 0000000000..d4275e9f3b --- /dev/null +++ b/reference/hazard_pointer/hazard_pointer/protect.md @@ -0,0 +1,101 @@ +# protect +* hazard_pointer[meta header] +* function[meta id-type] +* std[meta namespace] +* hazard_pointer[meta class] +* cpp26[meta cpp] + +```cpp +template +T* protect(const atomic& src) noexcept; +``` + +## 概要 +アトミックオブジェクト`src`が現在指しているオブジェクトを、このハザードポインタで保護する。 + +保護に成功すると、`src`が指していたオブジェクトは、この保護が解除されるまで、[`retire()`](../hazard_pointer_obj_base/retire.md)されても回収されない。 + + +## テンプレートパラメータ制約 +- `T`はハザードポインタで保護可能 (hazard-protectable) な型であること。 + + +## 事前条件 +- `*this`が空でないこと。 + + +## 効果 +以下と等価である: + +```cpp +T* ptr = src.load(memory_order::relaxed); +while (!try_protect(ptr, src)) {} +return ptr; +``` +* src.load[link /reference/atomic/atomic/load.md] +* memory_order::relaxed[link /reference/atomic/memory_order.md] +* try_protect[link try_protect.md] + + +## 戻り値 +保護したオブジェクトを指すポインタ。 + + +## 例外 +投げない + + +## 例 +```cpp example +#include +#include +#include + +struct Data : std::hazard_pointer_obj_base { + int value; + explicit Data(int v) : value(v) {} +}; + +std::atomic data{new Data(42)}; + +int main() +{ + std::hazard_pointer h = std::make_hazard_pointer(); + + // data が指すオブジェクトを保護して安全に参照する + Data* p = h.protect(data); + std::println("{}", p->value); + + // 後始末: 共有データが指すオブジェクトを回収予約する + data.load()->retire(); +} +``` +* h.protect[color ff0000] +* std::make_hazard_pointer[link ../make_hazard_pointer.md] +* data.load()[link /reference/atomic/atomic/load.md] +* retire()[link ../hazard_pointer_obj_base/retire.md] + +### 出力 +``` +42 +``` + + +## バージョン +### 言語 +- C++26 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 +- [`std::hazard_pointer::try_protect`](try_protect.md) +- [`std::hazard_pointer::reset_protection`](reset_protection.md) + + +## 参照 +- [P2530R3 Hazard Pointers for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2530r3.pdf) diff --git a/reference/hazard_pointer/hazard_pointer/reset_protection.md b/reference/hazard_pointer/hazard_pointer/reset_protection.md new file mode 100644 index 0000000000..951a639608 --- /dev/null +++ b/reference/hazard_pointer/hazard_pointer/reset_protection.md @@ -0,0 +1,66 @@ +# reset_protection +* hazard_pointer[meta header] +* function[meta id-type] +* std[meta namespace] +* hazard_pointer[meta class] +* cpp26[meta cpp] + +```cpp +template +void reset_protection(const T* ptr) noexcept; // (1) C++26 +void reset_protection(nullptr_t = nullptr) noexcept; // (2) C++26 +``` +* nullptr_t[link /reference/cstddef/nullptr_t.md] + +## 概要 +- (1): このハザードポインタが保護する対象を`*ptr`に変更する(現在の保護期間を終了する)。 +- (2): このハザードポインタの保護を解除し、非関連 (unassociated) 状態にする。 + + +## テンプレートパラメータ制約 +- (1): `T`はハザードポインタで保護可能 (hazard-protectable) な型であること。 + + +## 事前条件 +- (1), (2): `*this`が空でないこと。 + + +## 効果 +- (1): `ptr`がヌルポインタ値の場合、(2)の`reset_protection()`を呼び出す。そうでない場合、このハザードポインタを`*ptr`に関連付け、それまでの保護期間を終了する。 +- (2): (効果は事後条件で規定される。) + + +## 事後条件 +- (2): `*this`が所有するハザードポインタは非関連状態となる。 + + +## 戻り値 +なし + + +## 計算量 +定数時間 + + +## 例外 +投げない + + +## バージョン +### 言語 +- C++26 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 +- [`std::hazard_pointer::protect`](protect.md) +- [`std::hazard_pointer::try_protect`](try_protect.md) + + +## 参照 +- [P2530R3 Hazard Pointers for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2530r3.pdf) diff --git a/reference/hazard_pointer/hazard_pointer/swap.md b/reference/hazard_pointer/hazard_pointer/swap.md new file mode 100644 index 0000000000..f1aa97b575 --- /dev/null +++ b/reference/hazard_pointer/hazard_pointer/swap.md @@ -0,0 +1,52 @@ +# swap +* hazard_pointer[meta header] +* function[meta id-type] +* std[meta namespace] +* hazard_pointer[meta class] +* cpp26[meta cpp] + +```cpp +void swap(hazard_pointer& other) noexcept; +``` + +## 概要 +他の`hazard_pointer`オブジェクトとハザードポインタの所有権を入れ替える。 + + +## 効果 +`*this`と`other`のハザードポインタの所有権を入れ替える。 + + +## 戻り値 +なし + + +## 例外 +投げない + + +## 備考 +- 所有されているハザードポインタは、入れ替えの前後で変化しない。入れ替え前に保護していたオブジェクトを引き続き保護し続ける。保護期間 (protection epoch) の終了や開始は発生しない。 + + +## 計算量 +定数時間 + + +## バージョン +### 言語 +- C++26 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 +- [`std::swap`](swap_free.md) + + +## 参照 +- [P2530R3 Hazard Pointers for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2530r3.pdf) diff --git a/reference/hazard_pointer/hazard_pointer/swap_free.md b/reference/hazard_pointer/hazard_pointer/swap_free.md new file mode 100644 index 0000000000..cdbd499b8e --- /dev/null +++ b/reference/hazard_pointer/hazard_pointer/swap_free.md @@ -0,0 +1,54 @@ +# swap (非メンバ関数) +* hazard_pointer[meta header] +* std[meta namespace] +* function[meta id-type] +* cpp26[meta cpp] + +```cpp +namespace std { + void swap(hazard_pointer& a, hazard_pointer& b) noexcept; +} +``` + +## 概要 +2つの`hazard_pointer`オブジェクトのハザードポインタの所有権を入れ替える。 + + +## 効果 +以下と等価である: + +```cpp +a.swap(b); +``` +* swap[link swap.md] + + +## 戻り値 +なし + + +## 例外 +投げない + + +## 計算量 +定数時間 + + +## バージョン +### 言語 +- C++26 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 +- [`std::hazard_pointer::swap`](swap.md) + + +## 参照 +- [P2530R3 Hazard Pointers for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2530r3.pdf) diff --git a/reference/hazard_pointer/hazard_pointer/try_protect.md b/reference/hazard_pointer/hazard_pointer/try_protect.md new file mode 100644 index 0000000000..1f91196897 --- /dev/null +++ b/reference/hazard_pointer/hazard_pointer/try_protect.md @@ -0,0 +1,65 @@ +# try_protect +* hazard_pointer[meta header] +* function[meta id-type] +* std[meta namespace] +* hazard_pointer[meta class] +* cpp26[meta cpp] + +```cpp +template +bool try_protect(T*& ptr, const atomic& src) noexcept; +``` + +## 概要 +`ptr`が指すオブジェクトをこのハザードポインタで保護してよいか試み、その後の`src`の値と一致しているかを確認する。 + +[`protect()`](protect.md)メンバ関数は内部でこの関数を成功するまで繰り返し呼び出す。ロックフリーなアルゴリズムで、保護の設定と再確認を1ステップで行いたい場合に使用する。 + + +## テンプレートパラメータ制約 +- `T`はハザードポインタで保護可能 (hazard-protectable) な型であること。 + + +## 事前条件 +- `*this`が空でないこと。 + + +## 効果 +以下の手順を順に実行する: + +1. 型`T*`の変数`old`を`ptr`の値で初期化する。 +2. [`reset_protection`](reset_protection.md)`(old)`を評価する。 +3. `src.`[`load`](/reference/atomic/atomic/load.md)`(`[`memory_order::acquire`](/reference/atomic/memory_order.md)`)`の値を`ptr`へ代入する。 +4. `old == ptr`が`false`の場合、[`reset_protection`](reset_protection.md)`()`を評価する。 + + +## 戻り値 +`old == ptr`。すなわち、保護しようとしたポインタが、保護後の`src`の値と一致していれば`true`。 + + +## 例外 +投げない + + +## 備考 +- 戻り値が`false`の場合、`ptr`には`src`の新しい値が格納されているので、再度この関数を呼び出して保護を試みることができる。 + + +## バージョン +### 言語 +- C++26 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 +- [`std::hazard_pointer::protect`](protect.md) +- [`std::hazard_pointer::reset_protection`](reset_protection.md) + + +## 参照 +- [P2530R3 Hazard Pointers for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2530r3.pdf) diff --git a/reference/hazard_pointer/hazard_pointer_obj_base.md b/reference/hazard_pointer/hazard_pointer_obj_base.md new file mode 100644 index 0000000000..ff28605310 --- /dev/null +++ b/reference/hazard_pointer/hazard_pointer_obj_base.md @@ -0,0 +1,113 @@ +# hazard_pointer_obj_base +* hazard_pointer[meta header] +* class template[meta id-type] +* std[meta namespace] +* cpp26[meta cpp] + +```cpp +namespace std { + template > + class hazard_pointer_obj_base; +} +``` +* default_delete[link /reference/memory/default_delete.md] + +## 概要 +`hazard_pointer_obj_base`は、ハザードポインタで保護する対象とする型の基底クラスである。 + +使用するときは、型`T`で`hazard_pointer_obj_base`を公開かつ非仮想で継承した上で、派生クラス`T`を`hazard_pointer_obj_base`のテンプレート引数にする(CRTP)。 + +```cpp +struct Data : std::hazard_pointer_obj_base { + // ... +}; +``` + +型`T`が、ちょうど1つの`public`かつ非仮想な基底クラス`hazard_pointer_obj_base`をもち、ほかに`hazard_pointer_obj_base`型の基底クラスをもたないとき、その型は「ハザードポインタで保護可能な型」(hazard-protectable type)となる。 + +テンプレートパラメータ`D`は、オブジェクトの削除方法を指定する関数オブジェクト型であり、既定では[`default_delete`](/reference/memory/default_delete.md)``(`delete`式による破棄)となる。 + + +## 適格要件 +- `T`は不完全型でもよいが、特殊化された`hazard_pointer_obj_base`のメンバが参照されるまでに完全型とすること。 +- `D`は関数オブジェクト型であり、`D`型の値`d`と`T*`型の値`ptr`に対して式`d(ptr)`が有効であること。 +- `D`型は要件 Cpp17DefaultConstructible および Cpp17MoveAssignable を満たすこと。 + + +## メンバ関数 + +| 名前 | 説明 | 対応バージョン | +|------|------|----------------| +| [`(constructor)`](hazard_pointer_obj_base/op_constructor.md) | コンストラクタ | C++26 | +| `(destructor)` | デストラクタ | C++26 | +| [`operator=`](hazard_pointer_obj_base/op_assign.md) | 代入演算子 | C++26 | +| [`retire`](hazard_pointer_obj_base/retire.md) | オブジェクト回収をスケジュールする | C++26 | + + +## 備考 +- このクラステンプレートに対する特殊化を追加するプログラムの動作は未定義である。 + + +## 例 +```cpp example +#include +#include +#include + +struct Data : std::hazard_pointer_obj_base { + int value; + explicit Data(int v) : value(v) {} +}; + +// 共有データを指すポインタ +std::atomic data{new Data(1)}; + +int main() +{ + // 読み込み側: ハザードポインタで保護してから参照する + std::hazard_pointer h = std::make_hazard_pointer(); + Data* p = h.protect(data); + std::println("{}", p->value); + + // 更新側: 差し替えて古いオブジェクトを回収予約する + Data* old = data.exchange(new Data(2)); + old->retire(); // 保護が解除されてから回収される + + // 最後に残ったオブジェクトも回収予約する + // (取り外したオブジェクトを retire し忘れると回収されずリークするので注意) + data.load()->retire(); +} +``` +* std::hazard_pointer_obj_base[color ff0000] +* std::make_hazard_pointer[link make_hazard_pointer.md] +* h.protect[link hazard_pointer/protect.md] +* old->retire()[link hazard_pointer_obj_base/retire.md] +* exchange[link /reference/atomic/atomic/exchange.md] +* data.load()[link /reference/atomic/atomic/load.md] + +### 出力 +``` +1 +``` + + +## バージョン +### 言語 +- C++26 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 +- [`std::hazard_pointer`](hazard_pointer.md) +- [`std::make_hazard_pointer`](make_hazard_pointer.md) +- [`rcu_obj_base`](/reference/rcu/rcu_obj_base.md) + + +## 参照 +- [P2530R3 Hazard Pointers for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2530r3.pdf) + - C++26で追加された diff --git a/reference/hazard_pointer/hazard_pointer_obj_base/op_assign.md b/reference/hazard_pointer/hazard_pointer_obj_base/op_assign.md new file mode 100644 index 0000000000..cac24210a1 --- /dev/null +++ b/reference/hazard_pointer/hazard_pointer_obj_base/op_assign.md @@ -0,0 +1,33 @@ +# operator= +* hazard_pointer[meta header] +* function[meta id-type] +* std[meta namespace] +* hazard_pointer_obj_base[meta class] +* cpp26[meta cpp] + +```cpp +protected: + hazard_pointer_obj_base& operator=(const hazard_pointer_obj_base&) = default; // (1) C++26 + hazard_pointer_obj_base& operator=(hazard_pointer_obj_base&&) = default; // (2) C++26 +``` + +## 概要 +- (1): コピー代入演算子 +- (2): ムーブ代入演算子 + +いずれも`protected`メンバであり、派生クラスからのみ使用できる。 + + +## バージョン +### 言語 +- C++26 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 参照 +- [P2530R3 Hazard Pointers for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2530r3.pdf) diff --git a/reference/hazard_pointer/hazard_pointer_obj_base/op_constructor.md b/reference/hazard_pointer/hazard_pointer_obj_base/op_constructor.md new file mode 100644 index 0000000000..bd621d1b72 --- /dev/null +++ b/reference/hazard_pointer/hazard_pointer_obj_base/op_constructor.md @@ -0,0 +1,35 @@ +# コンストラクタ +* hazard_pointer[meta header] +* function[meta id-type] +* std[meta namespace] +* hazard_pointer_obj_base[meta class] +* cpp26[meta cpp] + +```cpp +protected: + hazard_pointer_obj_base() = default; // (1) C++26 + hazard_pointer_obj_base(const hazard_pointer_obj_base&) = default; // (2) C++26 + hazard_pointer_obj_base(hazard_pointer_obj_base&&) = default; // (3) C++26 +``` + +## 概要 +- (1): デフォルトコンストラクタ +- (2): コピーコンストラクタ +- (3): ムーブコンストラクタ + +いずれも`protected`メンバであり、派生クラスからのみ使用できる。 + + +## バージョン +### 言語 +- C++26 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 参照 +- [P2530R3 Hazard Pointers for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2530r3.pdf) diff --git a/reference/hazard_pointer/hazard_pointer_obj_base/retire.md b/reference/hazard_pointer/hazard_pointer_obj_base/retire.md new file mode 100644 index 0000000000..85be9cab15 --- /dev/null +++ b/reference/hazard_pointer/hazard_pointer_obj_base/retire.md @@ -0,0 +1,103 @@ +# retire +* hazard_pointer[meta header] +* function[meta id-type] +* std[meta namespace] +* hazard_pointer_obj_base[meta class] +* cpp26[meta cpp] + +```cpp +void retire(D d = D()) noexcept; +``` + +## 概要 +ハザードポインタで保護されるオブジェクトの回収 (reclamation) をスケジュールする。 + +このオブジェクトを削除済みとして登録し、どのハザードポインタからも指されていないことが確認された時点で、削除器`d`によって回収 (破棄) されるようにする。 + + +## 適格要件 +- クラステンプレートパラメータ`T`が、ハザードポインタで保護可能 (hazard-protectable) な型であること。すなわち、 + - `hazard_pointer_obj_base`型を唯一の基底クラスとして持ち、かつ + - その基底は公開 (public) かつ非仮想基底クラスであり、かつ + - 型`T2`, `D2`の他の組合せに対して`hazard_pointer_obj_base`型を基底クラスとして持たないこと。 + + +## 事前条件 +- `*this`が型`T`のオブジェクト`x`の基底クラスサブオブジェクトであること。 +- `x`が回収予約されていないこと。任意のオブジェクトの回収予約は高々1回だけ行える。 +- `D`型の説明用メンバ変数`deleter`への`d`のムーブ代入が例外で終了しないこと。 + + +## 効果 +- `deleter =` [`std::move`](/reference/utility/move.md)`(d)`を評価して`x`の削除器として設定し、`x`を回収予約する。 +- 回収可能となったオブジェクトを回収する可能性がある。 + +回収は、削除器に`x`へのポインタを渡して呼び出すことで行われる。この呼び出しが例外で終了した場合の動作は未定義である。 + + +## 戻り値 +なし + + +## 例外 +投げない + + +## 備考 +- ライブラリが回収 (破棄) するのは、`retire()`に渡されたオブジェクトだけである。**データ構造から取り外したオブジェクトを`retire()`し忘れると、そのオブジェクトは回収されずメモリリークになる**ので注意すること。ガベージコレクションのように未参照オブジェクトが自動的に回収されるわけではない。 +- 回収は、この`retire()`の呼び出し時に即座に行われるとは限らない。実際の回収 (削除器の呼び出し) は、どのハザードポインタからも指されていないことが確認できたオブジェクトに対して、後続の`retire()`や[`make_hazard_pointer()`](../make_hazard_pointer.md)などのライブラリ呼び出しの中で、まとめて (償却的に) 行われうる。遅くともプログラムの終了までには回収される。 + + +## 例 +```cpp example +#include +#include +#include + +struct Data : std::hazard_pointer_obj_base { + int value; + explicit Data(int v) : value(v) {} +}; + +std::atomic data{new Data(1)}; + +int main() +{ + // 新しいデータで差し替え、古いデータを回収予約する + Data* old = data.exchange(new Data(2)); + old->retire(); // 保護しているスレッドがいなくなったら回収される + + std::println("{}", data.load()->value); + + // 最後に残ったオブジェクトも回収予約する + data.load()->retire(); +} +``` +* retire()[color ff0000] +* exchange[link /reference/atomic/atomic/exchange.md] +* load[link /reference/atomic/atomic/load.md] + +### 出力 +``` +2 +``` + + +## バージョン +### 言語 +- C++26 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 +- [`std::hazard_pointer::protect`](../hazard_pointer/protect.md) +- [`rcu_obj_base::retire`](/reference/rcu/rcu_obj_base/retire.md) + + +## 参照 +- [P2530R3 Hazard Pointers for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2530r3.pdf) diff --git a/reference/hazard_pointer/make_hazard_pointer.md b/reference/hazard_pointer/make_hazard_pointer.md new file mode 100644 index 0000000000..dd0caa5ee3 --- /dev/null +++ b/reference/hazard_pointer/make_hazard_pointer.md @@ -0,0 +1,83 @@ +# make_hazard_pointer +* hazard_pointer[meta header] +* std[meta namespace] +* function[meta id-type] +* cpp26[meta cpp] + +```cpp +namespace std { + hazard_pointer make_hazard_pointer(); +} +``` +* hazard_pointer[link hazard_pointer.md] + +## 概要 +新しいハザードポインタを構築し、それを所有する[`hazard_pointer`](hazard_pointer.md)オブジェクトを返す。 + + +## 効果 +ハザードポインタを構築する。 + + +## 戻り値 +新しく構築したハザードポインタを所有する[`hazard_pointer`](hazard_pointer.md)オブジェクト。 + + +## 例外 +ハザードポインタ用のメモリを確保できなかった場合、[`std::bad_alloc`](/reference/new/bad_alloc.md)を送出する可能性がある。 + + +## 例 +```cpp example +#include +#include +#include + +struct Data : std::hazard_pointer_obj_base { + int value; + explicit Data(int v) : value(v) {} +}; + +std::atomic data{new Data(7)}; + +int main() +{ + // ハザードポインタを構築する + std::hazard_pointer h = std::make_hazard_pointer(); + + Data* p = h.protect(data); + std::println("{}", p->value); + + // 後始末: 共有データが指すオブジェクトを回収予約する + data.load()->retire(); +} +``` +* std::make_hazard_pointer[color ff0000] +* std::hazard_pointer_obj_base[link hazard_pointer_obj_base.md] +* h.protect[link hazard_pointer/protect.md] +* data.load()[link /reference/atomic/atomic/load.md] +* retire()[link hazard_pointer_obj_base/retire.md] + +### 出力 +``` +7 +``` + + +## バージョン +### 言語 +- C++26 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 +- [`std::hazard_pointer`](hazard_pointer.md) + + +## 参照 +- [P2530R3 Hazard Pointers for C++26](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2530r3.pdf) diff --git a/reference/hazard_pointer/make_hazard_pointer_batch.md b/reference/hazard_pointer/make_hazard_pointer_batch.md new file mode 100644 index 0000000000..3119628228 --- /dev/null +++ b/reference/hazard_pointer/make_hazard_pointer_batch.md @@ -0,0 +1,105 @@ +# make_hazard_pointer_batch +* hazard_pointer[meta header] +* std[meta namespace] +* function[meta id-type] +* cpp29[meta cpp] + +```cpp +namespace std { + void make_hazard_pointer_batch(span batch); // C++29 +} +``` +* span[link /reference/span/span.md] +* hazard_pointer[link hazard_pointer.md] + +## 概要 +複数のハザードポインタを、まとめて構築する。 + +`batch`に含まれる空の[`hazard_pointer`](hazard_pointer.md)オブジェクトそれぞれに、新しく構築したハザードポインタを所有させる。[`make_hazard_pointer()`](make_hazard_pointer.md)を個別に呼び出すよりも、複数のハザードポインタをまとめて構築することでレイテンシを低減できる。 + + +## 効果 +例外が送出された場合、何の効果も持たない (強い例外安全性の保証)。 + +そうでなければ、`batch`の各要素`e`のうち`e.`[`empty()`](hazard_pointer/empty.md)が`true`であるものについて、ハザードポインタを構築し、`e`をそのハザードポインタの所有者にする。 + + +## 戻り値 +なし + + +## 例外 +新しく構築するハザードポインタのいずれかのメモリを確保できなかった場合、[`std::bad_alloc`](/reference/new/bad_alloc.md)を送出する可能性がある。 + + +## 備考 +- 既に非空 (ハザードポインタを所有している) の要素は変更されない。 + + +## 例 +```cpp example +#include +#include +#include +#include + +struct Data : std::hazard_pointer_obj_base { + int value; + explicit Data(int v) : value(v) {} +}; + +std::atomic d0{new Data(1)}; +std::atomic d1{new Data(2)}; + +int main() +{ + // 2つのハザードポインタをまとめて構築する (個別構築より低レイテンシ) + std::array hp; + std::make_hazard_pointer_batch(hp); + + // それぞれで別の共有データを保護する + Data* p0 = hp[0].protect(d0); + Data* p1 = hp[1].protect(d1); + std::println("{} {}", p0->value, p1->value); + + // まとめて破棄する + std::clear_hazard_pointer_batch(hp); + + // 後始末: 共有データを回収予約する + d0.load()->retire(); + d1.load()->retire(); +} +``` +* std::make_hazard_pointer_batch[color ff0000] +* std::hazard_pointer_obj_base[link hazard_pointer_obj_base.md] +* hp[0].protect[link hazard_pointer/protect.md] +* std::clear_hazard_pointer_batch[link clear_hazard_pointer_batch.md] +* load[link /reference/atomic/atomic/load.md] +* retire()[link hazard_pointer_obj_base/retire.md] + +### 出力 +``` +1 2 +``` + + +## バージョン +### 言語 +- C++29 + +### 処理系 +- [Clang](/implementation.md#clang): ?? +- [GCC](/implementation.md#gcc): ?? +- [ICC](/implementation.md#icc): ?? +- [Visual C++](/implementation.md#visual_cpp): ?? + + +## 関連項目 +- [`std::make_hazard_pointer`](make_hazard_pointer.md) +- [`std::clear_hazard_pointer_batch`](clear_hazard_pointer_batch.md) +- [`std::hazard_pointer`](hazard_pointer.md) + + +## 参照 +- [P3428R4 Hazard Pointer Batches](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3428r4.pdf) + - C++29で追加された diff --git a/reference/rcu.md b/reference/rcu.md index 6801cb76ab..f0d6fb9f0c 100644 --- a/reference/rcu.md +++ b/reference/rcu.md @@ -29,7 +29,7 @@ RCU同期メカニズムは、複数スレッド間で共有されるリンク ## 関連項目 -- [``](hazard_pointer.md.nolink) +- [``](hazard_pointer.md) ## 参照