- memory[meta header]
- std[meta namespace]
- class template[meta id-type]
- cpp20[meta cpp]
namespace std {
template <class T> struct atomic; // 先行宣言
template <class T> struct atomic<shared_ptr<T>>;
template <class T> struct atomic<weak_ptr<T>>;
}- shared_ptr[link shared_ptr.md]
- weak_ptr[link weak_ptr.md]
<memory>ヘッダでは、std::shared_ptrとstd::weak_ptrクラスに対するstd::atomicクラスの特殊化を定義する。
これらの特殊化を使用することで、共通のスマートポインタオブジェクトに対する複数スレッドでの操作をアトミックに行える。
C++23でconstexpr atomic(nullptr_t) noexceptコンストラクタが追加され、非アトミックなshared_ptr・weak_ptrと同様に、constinitを使ってnullptrから定数初期化できるようになった:
// グローバル変数を、動的初期化ではなく定数初期化する
constinit std::atomic<std::shared_ptr<int>> g_resource{nullptr};非アトミックなshared_ptrではconstinit std::shared_ptr<int> p{nullptr};が可能であったが、C++20時点のatomic<shared_ptr<T>>はnullptrを受け取るコンストラクタ経路(nullptrから一時オブジェクトのshared_ptrを構築し、atomic(shared_ptr<T>)コンストラクタに渡す)がconstexprでなかったため、constinitによる定数初期化ができなかった。この非対称性が解消された。
constinitによる定数初期化には以下の利点がある:
- 静的初期化順序問題 (static initialization order fiasco) の回避 : グローバル・名前空間スコープのオブジェクトを動的初期化すると、ほかの翻訳単位のグローバル変数の初期化との実行順序が未規定となり、初期化前のオブジェクトにアクセスしてしまう危険がある。定数初期化されるオブジェクトはプログラム開始前に初期化が完了しているため、どの動的初期化よりも先に初期化済みであることが保証され、この問題を避けられる
- 動的初期化のオーバーヘッド排除 : 実行時に初期化コードが走らない
| 名前 | 説明 | 対応バージョン |
|---|---|---|
(constructor) |
コンストラクタ | C++20 |
constexpr atomic(nullptr_t) noexcept |
nullptrから構築する |
C++23 |
~atomic() = default |
デストラクタ | C++20 |
operator= |
代入演算子 | C++20 |
is_lock_free |
オブジェクトがロックフリーに振る舞えるかを判定する | C++20 |
store |
値を書き込む | C++20 |
load |
値を読み込む | C++20 |
operator T |
型Tへの変換演算子 | C++20 |
exchange |
値を入れ替える | C++20 |
compare_exchange_weak |
弱い比較で値を入れ替える | C++20 |
compare_exchange_strong |
強い比較で値を入れ替える | C++20 |
wait |
起床されるまで待機する | C++20 |
notify_one |
待機しているスレッドをひとつ起床させる | C++20 |
notify_all |
待機している全てのスレッドを起床させる | C++20 |
| 名前 | 説明 | 対応バージョン |
|---|---|---|
value_type |
要素型となるテンプレートパラメータの型T。shared_ptrに対する特殊化ではshared_ptr<T>となる。weak_ptrに対する特殊化ではweak_ptr<T>となる |
C++20 |
| 名前 | 説明 | 対応バージョン |
|---|---|---|
static constexpr bool is_always_lock_free |
型Tに対するアトミック操作が常にロックフリー (非ミューテックス) で動作する場合はtrue、そうでなければfalse |
C++20 |
#include <iostream>
#include <memory>
#include <thread>
std::atomic<std::shared_ptr<int>> resource;
// Producer-Consumerパターン。
// 供給者スレッドがデータを作成し、消費者スレッドが供給されたデータを使用する
void producer() {
std::shared_ptr<int> x{new int(3)};
resource.store(x);
}
void consumer() {
// データが供給されたら、resourceとyを入れ替える (resourceが空になり、yにデータが入る)。
std::shared_ptr<int> y;
while (!(y = resource.exchange(y))) {
}
std::cout << *y << std::endl;
}
int main()
{
std::thread consumer_thread{consumer};
std::thread producer_thread{producer};
consumer_thread.join();
producer_thread.join();
}- std::atomic<std::shared_ptr>[color ff0000]
- resource.store[link /reference/atomic/atomic/store.md]
- resource.exchange[link /reference/atomic/atomic/exchange.md]
- consumer_thread.join()[link /reference/thread/thread/join.md]
- producer_thread.join()[link /reference/thread/thread/join.md]
3
- C++20
- Clang:
- GCC:
- Visual C++: ??
- P0718R2 Revising
atomic_shared_ptrfor C++20 - cplusplus/draft #2824 - add forward declaration of
atomicclass foratomic<shared_ptr<T>>(P0718R2) - P1644R0 Add wait/notify to
atomic<shared_ptr<T>> - P3037R6
constexpr std::shared_ptrand friends - LWG Issue 3661.
constinit atomic<shared_ptr<T>> a(nullptr);should work- C++23で、
nullptrから構築するconstexpr atomic(nullptr_t) noexceptコンストラクタが追加された
- C++23で、