std::atomic_fetch_sub,std::atomic_fetch_sub_explicit (3) - Linux Man Pages

std::atomic_fetch_sub,std::atomic_fetch_sub_explicit: std::atomic_fetch_sub,std::atomic_fetch_sub_explicit

NAME

std::atomic_fetch_sub,std::atomic_fetch_sub_explicit - std::atomic_fetch_sub,std::atomic_fetch_sub_explicit

Synopsis


Defined in header <atomic>
template< class T >
T atomic_fetch_sub( std::atomic<T>* obj,
typename std::atomic<T>::difference_type arg ) noexcept;
template< class T >
T atomic_fetch_sub( volatile std::atomic<T>* obj,
typename std::atomic<T>::difference_type arg ) noexcept;
template< class T > (1)
T atomic_fetch_sub_explicit( std::atomic<T>* obj,
typename std::atomic<T>::difference_type arg,
std::memory_order order ) noexcept; (2)
template< class T >
T atomic_fetch_sub_explicit( volatile std::atomic<T>* obj,
typename std::atomic<T>::difference_type arg,
std::memory_order order ) noexcept;


Performs atomic subtraction. Atomically subtracts arg from 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_sub(arg)
2) obj->fetch_sub(arg, order)

Parameters


obj - pointer to the atomic object to modify
arg - the value to subtract from 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.

Possible implementation


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

Example


Multiple threads may use fetch_sub to concurrently process an indexed container
// Run this code


  #include <string>
  #include <thread>
  #include <vector>
  #include <iostream>
  #include <atomic>
  #include <numeric>


  const int N = 50;
  std::atomic<int> cnt;
  std::vector<int> data(N);


  void reader(int id)
  {
      for (;;) {
          int idx = atomic_fetch_sub_explicit(&cnt, 1, std::memory_order_relaxed);
          if (idx >= 0) {
              std::cout << "reader " << std::to_string(id) << " processed item "
                        << std::to_string(data[idx]) << '\n';
          } else {
              std::cout << "reader " << std::to_string(id) << " done\n";
              break;
          }
      }
  }


  int main()
  {
      std::iota(data.begin(), data.end(), 1);
      cnt = data.size() - 1;


      std::vector<std::thread> v;
      for (int n = 0; n < 5; ++n) {
          v.emplace_back(reader, n);
      }
      for (auto& t : v) {
          t.join();
      }
  }

Output:


  reader 2 processed item 50
  reader 1 processed item 44
  reader 4 processed item 46
  <....>
  reader 0 done
  reader 4 done
  reader 3 done


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 subtracts the argument from the value stored in the atomic object and obtains the value held previously
fetch_sub (public member function of std::atomic<T>)


atomic_fetch_add
atomic_fetch_add_explicit adds a non-atomic value to an atomic object and obtains the previous value of the atomic
                          (function template)
(C++11)
(C++11)