名前空間
変種
操作

アトミック型

From cppreference.com
< c‎ | language

目次

[編集] 構文

_Atomic ( 型名 ) (1) (C11 以降)
_Atomic 型名 (2) (C11 以降)
1) 型指定子として使用します。これは新しいアトミック型を指定します。
2) 型修飾子として使用します。これは 型名 のアトミックバージョンを指定します。この場合、constvolatile、および restrict と混在させることができます。ただし、他の修飾子とは異なり、型名 のアトミックバージョンは、サイズ、アラインメント、およびオブジェクト表現が異なる場合があります。
型名 - 配列型または関数型以外の任意の型。 (1) の場合、型名 はアトミック型または cvr 修飾されている型であってもなりません。

ヘッダー <stdatomic.h> は、組み込み型およびライブラリ型でのこのキーワードの使用を簡素化する、多くの便利な型エイリアスatomic_bool から atomic_uintmax_t まで)を定義します。

_Atomic const int* p1;  // p is a pointer to an atomic const int
const atomic_int* p2;   // same
const _Atomic(int)* p3; // same

コンパイラによってマクロ定数 __STDC_NO_ATOMICS__ が定義されている場合、キーワード _Atomic は提供されません。

[編集] 説明

アトミック型のオブジェクトは、データ競合から解放される唯一のオブジェクトです。つまり、それらは複数のスレッドによって同時に変更されたり、一方のスレッドによって変更され、もう一方のスレッドによって読み取られたりする可能性があります。

各アトミックオブジェクトには、そのオブジェクトに対して行われた変更の合計順序である、関連付けられた *変更順序* があります。あるスレッドの視点から、アトミック変数 M の変更 A が同じアトミック変数 M の変更 B よりも *先行している* 場合、M の変更順序では AB よりも前に現れます。

各アトミックオブジェクトには独自の変更順序がありますが、単一の合計順序は存在しないことに注意してください。異なるスレッドは、異なるアトミックオブジェクトへの変更を異なる順序で観測する可能性があります。

すべての原子操作で保証される 4 つのコヒーレンス種類があります。

  1. 書き込み-書き込みコヒーレンス: アトミックオブジェクト M を変更する操作 A が、M を変更する操作 B よりも *先行している* 場合、AM の変更順序で B よりも前に現れます。
  2. 読み取り-読み取りコヒーレンス: アトミックオブジェクト M の値計算 AM の値計算 B よりも先行し、AM に対する副作用 X から値を取得する場合、B によって計算された値は、X によって格納された値、または M に対する副作用 Y (`X` よりも `M` の変更順序で後に現れる)によって格納された値のいずれかです。
  3. 読み取り-書き込みコヒーレンス: アトミックオブジェクト M の値計算 A が、M に対する操作 B よりも *先行している* 場合、AM に対する副作用 X から値を取得し、XM の変更順序で B よりも前に現れます。
  4. 書き込み-読み取りコヒーレンス: アトミックオブジェクト M に対する副作用 XM の値計算 B よりも *先行している* 場合、B の評価は X から値を取得するか、または M の変更順序で X よりも後に現れる副作用 Y から値を取得します。

一部のアトミック操作は同期操作でもあり、追加のリリースセマンティクス、アquireセマンティクス、または順序整合セマンティクスを持つ場合があります。memory_order を参照してください。

組み込みの インクリメントおよびデクリメント演算子 および 複合代入 は、全体的な順序整合順序付け(memory_order_seq_cst を使用する場合と同様)を持つ読み取り-変更-書き込みアトミック操作です。それほど厳密でない同期セマンティクスが必要な場合は、代わりに 標準ライブラリ関数 を使用できます。

アトミックプロパティは、lvalue 式に対してのみ意味があります。lvalue から rvalue への変換(アトミック場所から CPU レジスタへのメモリ読み取りをモデル化します)は、他の修飾子とともにアトミック性を剥奪します。

[編集] 注記

アトミックな構造体/共用体のメンバーへのアクセスは未定義の動作です。

ライブラリ型 sig_atomic_t は、アトミック性のみを提供し、スレッド間同期やメモリ順序付けは提供しません。

volatile 型は、スレッド間同期、メモリ順序付け、またはアトミック性を提供しません。

実装は、C における _Atomic(T) の表現が、すべての可能な型 T に対して C++ の std::atomic<T> の表現と同じであることを保証することが推奨されます。アトミック性およびメモリ順序付けを保証するために使用されるメカニズムは互換性があるべきです。

[編集] キーワード

_Atomic

[編集]

#include <stdatomic.h>
#include <stdio.h>
#include <threads.h>
 
atomic_int acnt;
int cnt;
 
int f(void* thr_data)
{
    for (int n = 0; n < 1000; ++n)
    {
        ++cnt;
        ++acnt;
        // for this example, relaxed memory order is sufficient, e.g.
        // atomic_fetch_add_explicit(&acnt, 1, memory_order_relaxed);
    }
    return 0;
}
 
int main(void)
{
    thrd_t thr[10];
    for (int n = 0; n < 10; ++n)
        thrd_create(&thr[n], f, NULL);
    for (int n = 0; n < 10; ++n)
        thrd_join(thr[n], NULL);
 
    printf("The atomic counter is %u\n", acnt);
    printf("The non-atomic counter is %u\n", cnt);
}

実行結果の例

The atomic counter is 10000
The non-atomic counter is 8644

[編集] 参照

  • C23標準 (ISO/IEC 9899:2024)
  • 6.7.2.4 アトミック型指定子 (p: TBD)
  • 7.17 アトミックス <stdatomic.h> (p: TBD)
  • C17標準 (ISO/IEC 9899:2018)
  • 6.7.2.4 アトミック型指定子 (p: 87)
  • 7.17 アトミックス <stdatomic.h> (p: 200-209)
  • C11標準 (ISO/IEC 9899:2011)
  • 6.7.2.4 アトミック型指定子 (p: 121)
  • 7.17 アトミックス <stdatomic.h> (p: 273-286)

[編集] 関連項目

並行性サポートライブラリ
C++ ドキュメントatomic について)
English 日本語 中文(简体) 中文(繁體)