Namespaces
Variants
Views
Actions

std::atomic_fetch_add, std::atomic_fetch_add_explicit

From cppreference.com
< cpp‎ | atomic
Revision as of 04:16, 29 October 2022 by Ramika (Talk | contribs)

 
 
Concurrency support library
Threads
(C++11)
(C++20)
this_thread namespace
(C++11)
(C++11)
(C++11)
Cooperative cancellation
Mutual exclusion
(C++11)
Generic lock management
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
Condition variables
(C++11)
Semaphores
Latches and Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
(C++11)
(C++11)
Safe Reclamation
(C++26)
Hazard Pointers
Atomic types
(C++11)
(C++20)
Initialization of atomic types
(C++11)(deprecated in C++20)
(C++11)(deprecated in C++20)
Memory ordering
Free functions for atomic operations
atomic_fetch_addatomic_fetch_add_explicit
(C++11)(C++11)
Free functions for atomic flags
 
Defined in header <atomic>
(1)
template< class T >

T atomic_fetch_add( std::atomic<T>* obj,

                    typename std::atomic<T>::difference_type arg ) noexcept;
template< class T >

T atomic_fetch_add( volatile std::atomic<T>* obj,

                    typename std::atomic<T>::difference_type arg ) noexcept;
(2)
template< class T >

T atomic_fetch_add_explicit( std::atomic<T>* obj,
                             typename std::atomic<T>::difference_type arg,

                             std::memory_order order ) noexcept;
template< class T >

T atomic_fetch_add_explicit( volatile std::atomic<T>* obj,
                             typename std::atomic<T>::difference_type arg,

                             std::memory_order order ) noexcept;

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:

1) obj->fetch_add(arg)
2) obj->fetch_add(arg, order)

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 synchronization 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.

Possible implementation

template< class T >
T atomic_fetch_add( std::atomic<T>* obj, typename std::atomic<T>::difference_type arg )
{
    return obj->fetch_add(arg);
}

Example

Single-writer/multiple-reader lock can be made with fetch_add. Note that this simplistic implementation is not lockout-free

#include <string>
#include <thread>
#include <vector>
#include <iostream>
#include <atomic>
#include <chrono>
 
// meaning of cnt:
// 5: readers and writer are in race. There are no active readers or writers.
//-1: writer won the race and readers are blocked.
// 4...0: there are 1...5 active readers, The writer is 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(std::chrono::milliseconds(1));
    }
}
 
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(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 2 sees 0
reader 3 sees 0
reader 1 sees 0
<...>
reader 2 sees 24
reader 4 sees 24
reader 1 sees 24

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 required because T is deduced from multiple arguments T is deduced from the atomic argument only

See also

atomically adds the argument to the value stored in the atomic object and obtains the value held previously
(public member function of std::atomic<T>) [edit]
subtracts a non-atomic value from an atomic object and obtains the previous value of the atomic
(function template) [edit]
C documentation for atomic_fetch_add, atomic_fetch_add_explicit