std::atomic_fetch_add, std::atomic_fetch_add_explicit
From cppreference.com
| ヘッダー <atomic> で定義 |
||
| template< class T > T atomic_fetch_add( std::atomic<T>* obj, |
(1) | (C++11以降) |
| template< class T > T atomic_fetch_add( volatile std::atomic<T>* obj, |
(2) | (C++11以降) |
| template< class T > T atomic_fetch_add_explicit( std::atomic<T>* obj, |
(3) | (C++11以降) |
| template< class T > T atomic_fetch_add_explicit( volatile std::atomic<T>* obj, |
(4) | (C++11以降) |
アトミックな加算を実行します。`obj`が指す値に`arg`をアトミックに加算し、`obj`が以前に保持していた値を返します。この操作は、以下が実行されたかのように行われます。
1,2) obj->fetch_add(arg)
3,4) obj->fetch_add(arg, order)
std::atomic<T>にfetch_addメンバがない場合(このメンバは整数型、浮動小数点型(C++20以降)、およびboolを除くポインタ型に対してのみ提供されます)、プログラムは不定形となります。
目次 |
[編集] パラメータ
| obj | - | 操作対象のアトミックオブジェクトへのポインタ |
| arg | - | アトミックオブジェクトに格納されている値に追加する値。 |
| order | - | メモリ同期順序 |
[編集] 戻り値
*objの修正順序において、この関数の効果の直前の値。
[編集] 例
単一ライター/複数リーダーロックはstd::atomic_fetch_addで作成できます。この単純な実装はロックフリーではないことに注意してください。
このコードを実行
#include <atomic> #include <chrono> #include <iostream> #include <string> #include <thread> #include <vector> using namespace std::chrono_literals; // meaning of cnt: // 5: readers and writer are in race. There are no active readers or writers. // 4...0: there are 1...5 active readers, The writer is blocked. // -1: writer won the race and readers are blocked. const int N = 5; // four concurrent readers are allowed std::atomic<int> cnt(N); std::vector<int> data; void reader(int id) { for (;;) { // lock while (std::atomic_fetch_sub(&cnt, 1) <= 0) std::atomic_fetch_add(&cnt, 1); // read if (!data.empty()) std::cout << ("reader " + std::to_string(id) + " sees " + std::to_string(*data.rbegin()) + '\n'); if (data.size() == 25) break; // unlock std::atomic_fetch_add(&cnt, 1); // pause std::this_thread::sleep_for(1ms); } } void writer() { for (int n = 0; n < 25; ++n) { // lock while (std::atomic_fetch_sub(&cnt, N + 1) != N) std::atomic_fetch_add(&cnt, N + 1); // write data.push_back(n); std::cout << "writer pushed back " << n << '\n'; // unlock std::atomic_fetch_add(&cnt, N + 1); // pause std::this_thread::sleep_for(1ms); } } int main() { std::vector<std::thread> v; for (int n = 0; n < N; ++n) v.emplace_back(reader, n); v.emplace_back(writer); for (auto& t : v) t.join(); }
出力
writer pushed back 0 reader 2 sees 0 reader 3 sees 0 reader 1 sees 0 <...> reader 2 sees 24 reader 4 sees 24 reader 1 sees 24
[編集] 不具合報告
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| P0558R1 | C++11 | 厳密な型一致が必要であったためTは複数の引数から推論された |
Tは推論されるのみobj から |
[編集] 関連項目
| 引数をアトミックオブジェクトに格納された値にアトミックに加算し、以前に保持されていた値を取得する ( std::atomic<T>のパブリックメンバ関数) | |
| (C++11)(C++11) |
アトミックオブジェクトから非アトミックな値を減算し、アトミックオブジェクトの以前の値を取得する (関数テンプレート) |