Defined in header <atomic> | |||
---|---|---|---|
(1) | (since C++11) | ||
| |||
| |||
(2) | (since C++11) | ||
| |||
| |||
(3) | (since C++11) | ||
| |||
| |||
(4) | (since C++11) | ||
| |||
|
Performs atomic addition.
1-2) 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: 1)
obj->fetch_add(arg)
2)
obj->fetch_add(arg, order)
3-4) Atomically increments the pointer value, pointed to by
obj
, by arg
, and returns the value obj
held previously. The operation is performed as if the following was executed: 3)
obj->fetch_add(arg)
4)
obj->fetch_add(arg, order)
Parameters
obj | - | pointer to the atomic object to modify |
arg | - | the value to add to the value stored in the atomic object |
order | - | the memory sycnhronization ordering for this operation: all values are permitted. |
Return value
The value immediately preceding the effects of this function in the modification order of *obj
.
Exceptions
noexcept
specification: noexcept
Possible implementation
First version | ||
---|---|---|
| ||
Second version | ||
|
Example
Single-writer/multiple-reader lock can be made with fetch_add. Note that this simplistic implementation is not lockout-free.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | #include <string> #include <thread> #include <vector> #include <iostream> #include <atomic> #include <chrono> // meaning of cnt: // 10: there are no active readers or writers. // 1...9: there are 9...1 readers active, The writer is blocked // 0: temporary value between fetch_sub and fetch_add in reader lock // -1: there is a writer active. The readers are blocked. const int N = 10; // nine concurrent readers are allowed std::atomic< int > cnt = ATOMIC_VAR_INIT(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() == 100) break ; // unlock std::atomic_fetch_add(&cnt, 1); // pause std::this_thread::sleep_for(std::chrono::milliseconds(1)); } } void writer() { for ( int n = 0; n < 100; ++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(std::chrono::milliseconds(1)); } } 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:
1 2 3 4 5 6 7 8 | writer pushed back 0 reader 8 sees 0 reader 3 sees 0 reader 1 sees 0 <...> reader 2 sees 99 reader 6 sees 99 reader 1 sees 99 |
See also
(C++11) | atomically adds the argument to the value stored in the atomic object and obtains the value held previously (public member function of std::atomic ) |
(C++11)(C++11) | subtracts a non-atomic value from an atomic object and obtains the previous value of the atomic (function template) |
C documentation for atomic_fetch_add, atomic_fetch_add_explicit |
Please login to continue.