atomic_fetch_add, atomic_fetch_add_explicit
| ヘッダ <stdatomic.h>で定義 |
||
| C atomic_fetch_add( volatile A* obj, M arg ); |
(1) | (C11 以降) |
| C atomic_fetch_add_explicit( volatile A* obj, M arg, memory_order order ); |
(2) | (C11 以降) |
obj が指す値を、obj の以前の値に arg を加算した結果でアトミックに置き換えます。そして、obj が以前に保持していた値を返します。この操作は読み取り-変更-書き込み操作です。最初のバージョンは memory_order_seq_cst に従ってメモリのアクセス順序を決定し、2番目のバージョンは order に従ってメモリのアクセス順序を決定します。
これは、すべての アトミックオブジェクト型 A に対して定義された 汎用関数 です。引数は、非 volatile アトミックオブジェクトと volatile (例:メモリマップドI/O)アトミックオブジェクトの両方のメモリアドレスを受け入れるために、volatile アトミック型へのポインタです。volatile アトミックオブジェクトにこの操作を適用した場合、volatile セマンティクスは保持されます。M は、A がアトミック整数型の場合は A に対応する非アトミック型、または A がアトミックポインタ型の場合は ptrdiff_t です。
汎用関数の名前がマクロであるか、外部リンケージで宣言された識別子であるかは未規定です。実際の関数にアクセスするためにマクロ定義が無効にされている場合(例: (atomic_fetch_add)(...) のように括弧で囲まれた場合)、またはプログラムが汎用関数と同じ名前の外部識別子を定義した場合、その動作は未定義です。
符号付き整数型の場合、算術演算は2の補数表現を使用すると定義されています。未定義の結果はありません。ポインタ型の場合、結果は未定義のアドレスになる可能性がありますが、それ以外の操作に未定義の動作はありません。
目次 |
[編集] パラメータ
| obj | - | 操作対象のアトミックオブジェクトへのポインタ |
| arg | - | アトミックオブジェクトに格納されている値に加算する値 |
| order | - | この操作のメモリ同期順序:すべての値が許可されます |
[編集] 戻り値
obj が指すアトミックオブジェクトが以前に保持していた値。
[編集] 例
#include <stdio.h> #include <threads.h> #include <stdatomic.h> atomic_int acnt; int cnt; int f(void* thr_data) { for(int n = 0; n < 1000; ++n) { atomic_fetch_add_explicit(&acnt, 1, memory_order_relaxed); // atomic ++cnt; // undefined behavior, in practice some updates missed } 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 9511
[編集] 参考文献
- C17標準 (ISO/IEC 9899:2018)
- 7.17.7.5 The atomic_fetch and modify generic functions (p: 208)
- C11標準 (ISO/IEC 9899:2011)
- 7.17.7.5 The atomic_fetch and modify generic functions (p: 284-285)
[編集] 関連項目
| アトミック減算 (関数) | |
| C++ ドキュメント (
atomic_fetch_add, atomic_fetch_add_explicit 用) | |