最終更新日時:
が更新

履歴 編集

class
<hazard_pointer>

std::hazard_pointer(C++26)

namespace std {
  class hazard_pointer;
}

概要

hazard_pointerは、1つのハザードポインタを所有するクラスである。

このクラスのオブジェクトは、「空 (empty)」であるか、ちょうど1つのハザードポインタを所有するかのいずれかである。ハザードポインタは同時に高々1つのスレッドから所有され、その所有スレッドだけが値を設定できる。ムーブのみ可能で、コピーはできない。

オブジェクトは通常、make_hazard_pointer()関数で構築する。参照したい共有オブジェクトをprotect()メンバ関数で保護すると、その保護が解除される (デストラクタやreset_protection()メンバ関数) まで、そのオブジェクトはretire()されても回収されない。

std::hazard_pointer h = std::make_hazard_pointer();
Data* p = h.protect(shared_ptr_atomic); // 保護開始
// ... *p を安全に参照できる ...
// h のスコープ終了で保護終了

メンバ関数

名前 説明 対応バージョン
(constructor) コンストラクタ C++26
(destructor) デストラクタ C++26
operator= ムーブ代入演算子 C++26
empty 空かどうかを判定する C++26
protect オブジェクトを保護する C++26
try_protect オブジェクトの保護を試みる C++26
reset_protection 保護を解除する C++26
swap 他のhazard_pointerオブジェクトと入れ替える C++26

非メンバ関数

名前 説明 対応バージョン
swap 2つのhazard_pointerオブジェクトを入れ替える C++26
make_hazard_pointer ハザードポインタを構築する C++26
make_hazard_pointer_batch 複数のハザードポインタをまとめて構築する C++29
clear_hazard_pointer_batch 複数のハザードポインタをまとめて破棄する C++29

#include <hazard_pointer>
#include <atomic>
#include <thread>
#include <print>

struct Data : std::hazard_pointer_obj_base<Data> {
  int value;
  explicit Data(int v) : value(v) {}
};

// 複数スレッドから並行にアクセスされる共有データ
std::atomic<Data*> 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();
}

出力例

0

バージョン

言語

  • C++26

処理系

関連項目

参照