std::atomic_fetch_add, std::atomic_fetch_add_explicit
<atomic>
T atomic_fetch_add( std::atomic <T>* obj,
T atomic_fetch_add( volatile std::atomic <T>* obj,
T atomic_fetch_add_explicit( std::atomic <T>* obj,
typename std::atomic <T>::difference_type arg,
T atomic_fetch_add_explicit( volatile std::atomic <T>* obj,
typename std::atomic <T>::difference_type arg,
Performs atomic addition. Atomically adds arg to the value pointed to by obj and returns the value obj held previously. The operation is performed as if the following was executed:
If std::atomic<T>
has no fetch_add
member (this member is only provided for integral , floating-point (since C++20) and pointer types except bool), the program is ill-formed.
[edit] Parameters
[edit] Return value
The value immediately preceding the effects of this function in the modification order of *obj.
[edit] Example
Single-writer/multiple-reader lock can be made with std::atomic_fetch_add
. Note that this simplistic implementation is not lockout-free.
#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(); }
Output:
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
[edit] Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
P0558R1 | C++11 | exact type match was required becauseT was deduced from multiple arguments
|
T is only deducedfrom obj |
[edit] See also
(public member function of
std::atomic<T>
) [edit]
(function template) [edit]