constexpr T* address() const noexcept;
概要
参照しているオブジェクトのアドレスを取得する。
この関数を必要とする状況
データ構造の要素へのアトミックアクセス
配列の各要素にアトミックアクセスする際、std::atomic
オブジェクトでは以下のように記述する。
std::array<std::atomic<int>, N> array;
int fetch_add_idx(std::atomic<int>* base, size_t i, int value) {
return base[i].fetch_add(value);
}
これをstd::atomic_ref
で記述する場合、アトミック性をもたせてアクセスするには、この関数を使用して以下のようにする。
int fetch_add_idx(std::atomic_ref<int> base, size_t i, int value) {
int* p = base.address();
return std::atomic_ref{*(p+i)}.fetch_add(value);
}
- fetch_add[link fetch_add.md
必要なときにのみアトミックアクセスする
以下の例では、複数のスレッドが並行にメモリにアクセスし、カウンタをインクリメントすることでアクセス終了を知らせている。最後のスレッドはメモリにアクセスする余分な処理を実行する必要があるが、並行にメモリにアクセスするほかのスレッドがないため、これらのアクセスはアトミックである必要がない:
void thread(atomic_ref<int>* data, atomic_ref<int> counter, int nthreads) {
data->fetch_add(42, memory_order_relaxed);
int* d = data->address(); // dataへの生ポインタを取得
data->~atomic_ref(); // このスレッドのデータへのatomic_refを破棄する
int pos = counter.fetch_add(1); // データの破棄が完了したことを伝える
if (pos != (nthreads - 1))
return;
// 最後のスレッド: アトミックアクセスする必要がない
int last_data = *d; // 非アトミックアクセス
// …
}
戻り値
*this
が参照するオブジェクトをアドレス値を返す
例外
投げない
例
#include <iostream>
#include <atomic>
#include <thread>
void f(std::atomic_ref<int> ar, int i) {
int* p = ar.address();
std::atomic_ref{p + i}.fetch_add(1);
}
int main()
{
int ar[3] = {};
std::thread t1{[&ar]{ f(std::atomic_ref{ar[0]}, 1); }};
std::thread t2{[&ar]{ f(std::atomic_ref{ar[0]}, 1); }};
t1.join();
t2.join();
std::cout << ar[1] << std::endl;
}
22
#include <iostream>
#include <atomic>
#include <thread>
void f(std::atomic_ref<int> ar, int i) {
int* p = ar.address();
std::atomic_ref{p + i}.fetch_add(1);
}
int main()
{
int ar[3] = {};
std::thread t1{[&ar]{ f(std::atomic_ref{ar[0]}, 1); }};
std::thread t2{[&ar]{ f(std::atomic_ref{ar[0]}, 1); }};
t1.join();
t2.join();
出力
2
バージョン
言語
- C++26
処理系
- Clang: 19.0 ❌
- GCC: 14 ❌
- Visual C++: ??