Difference between revisions of "cpp/atomic/atomic fetch add"
(fixed example) |
|||
Line 74: | Line 74: | ||
return obj->fetch_add(arg); | return obj->fetch_add(arg); | ||
} | } | ||
+ | }} | ||
+ | |||
+ | ===Example=== | ||
+ | {{example cpp | ||
+ | | Single-writer/multiple-reader lock can be made with fetch_add. Note that this simplistic implementation is not lockout-free | ||
+ | | code= | ||
+ | #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= | ||
+ | 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 | ||
}} | }} | ||
Revision as of 19:27, 4 January 2012
Template:cpp/atomic/sidebar Template:ddcl list begin <tr class="t-dsc-header">
<td><atomic>
<td></td> <td></td> </tr> <tr class="t-dcl ">
<td >Integral atomic_fetch_add( std::atomic<Integral>* obj, Integral arg );
<td > (1) </td> <td > (since C++11) </td> </tr> <tr class="t-dcl ">
<td >Integral atomic_fetch_add( volatile std::atomic<Integral>* obj, Integral arg );
<td > (2) </td> <td > (since C++11) </td> </tr> <tr class="t-dcl ">
<td >Integral atomic_fetch_add_explicit( std::atomic<Integral>* obj, Integral arg, std::memory_order order);
<td > (3) </td> <td > (since C++11) </td> </tr> <tr class="t-dcl ">
<td >Integral atomic_fetch_add_explicit( volatile std::atomic<Integral>* obj, Integral arg, std::memory_order order);
<td > (4) </td> <td > (since C++11) </td> </tr> <tr class="t-dcl ">
<td >T* atomic_fetch_add( std::atomic<T*>* obj, std::ptrdiff_t arg );
<td > (5) </td> <td > (since C++11) </td> </tr> <tr class="t-dcl ">
<td >T* atomic_fetch_add( volatile std::atomic<T*>* obj, std::ptrdiff_t arg );
<td > (6) </td> <td > (since C++11) </td> </tr> <tr class="t-dcl ">
<td >T* atomic_fetch_add_explicit( std::atomic<T*>* obj, std::ptrdiff_t arg, std::memory_order order);
<td > (7) </td> <td > (since C++11) </td> </tr> <tr class="t-dcl ">
<td >T* atomic_fetch_add_explicit( volatile std::atomic<T*>* obj, std::ptrdiff_t arg, std::memory_order order);
<td > (8) </td> <td > (since C++11) </td> </tr> Template:ddcl list end
1-2) Atomically adds arg
to the value pointed to by obj
and returns the value obj
held previously, as if by Template:cpp
3-4) Atomically adds arg
to the value pointed to by obj
and returns the value obj
held previously, as if by Template:cpp
5-6) Atomically increments the pointer value, pointed to by obj
, by arg
, and returns the value obj
held previously, as if by Template:cpp
7-8) Atomically increments the pointer value, pointed to by obj
, by arg
, and returns the value obj
held previously, as if by Template:cpp
Contents |
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 held previously by the atomic object pointed to by obj