Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++, c++11, std::atomic member functions

Tags:

c++

c++11

atomic

I am trying to use std::atomic library.

  1. What's the difference between specialized and non-specialized atomic member functions?
  2. What's the difference (if there is any) between following functions?
  3. operator= stores a value into an atomic object (public member function) v.s. store (C++11) atomically replaces the value of the atomic object with a non-atomic argument (public member function)
  4. operator T() loads a value from an atomic object (public member function) v.s. load (C++11) atomically obtains the value of the atomic object (public member function).
  5. operator+= v.s. fetch_add
  6. operator-= v.s. fetch_sub
  7. operator&= v.s. fetch_and
  8. operator|= v.s. fetch_or
  9. operator^= v.s. fetch_xor
  10. What's the downside of declare a variable as atomic v.s. a non-atomic variable. For example, what's the downside of std::atomic<int> x v.s. int x? In other words, how much is the overhead of an atomic variable?
  11. Which one has more overhead? An atomic variable, v.s. a normal variable protected by a mutex?

Here is the reference to my quesitons. http://en.cppreference.com/w/cpp/atomic/atomic

like image 248
2607 Avatar asked Mar 04 '12 03:03

2607


2 Answers

Not an expert, but I'll try:

  1. The specializations (for built-in types such as int) contain additional operations such as fetch_add. Non-specialized forms (user defined types) will not contain these.
  2. operator= returns its argument, store does not. Also, non-operators allow you to specify a memory order. The standard says operator= is defined in terms of store.
  3. Same as above, although it returns the value of load.
  4. Same as above
  5. Same as above
  6. Same as above
  7. Same as above
  8. Same as above
  9. Same as above
  10. They do different things. It's undefined behavior to use an int in the way you would use std::atomic_int.
  11. You can assume the overhead is int <= std::atomic <= int and std::mutex where <= means 'less overhead'. So it's likely better than locking with a mutex (especially for built-in types), but worse than int.
like image 108
Pubby Avatar answered Oct 21 '22 03:10

Pubby


What's the difference between specialized and non-specialized atomic member functions?

As can be seen in the synposis of these classes on the standard (§29.5), there are three different sets of member functions:

  • the most generic one provides only store, load, exchange, and compare-exchange operations;
  • the specializations for integral types provide atomic arithmetic and bitwise operations, in addition to the generic ones;
  • the specialization for pointers provides pointer arithmetic operations in addition to the generic ones.

What's the difference (if there is any) between following functions?

operator= stores a value into an atomic object (public member function) v.s. store (C++11) atomically replaces the value of the atomic object with a non-atomic argument (public member function)

(...)

The main functional difference is that the non-operator versions (§29.6.5, paragraphs 9-17 and more) have an extra parameter for specifying the desired memory ordering (§29.3/1). The operator versions use the sequential consistency memory ordering:

void A::store(C desired, memory_order order = memory_order_seq_cst) volatile noexcept;
void A::store(C desired, memory_order order = memory_order_seq_cst) noexcept;

Requires: The order argument shall not be memory_order_consume, memory_order_acquire, nor memory_order_acq_rel.

Effects: Atomically replaces the value pointed to by object or by this with the value of desired. Memory is affected according to the value of order.

C A::operator=(C desired) volatile noexcept;
C A::operator=(C desired) noexcept;

Effects: store(desired)

Returns: desired

The non-operator forms are advantageous because sequential consistency is not always necessary, and it is potentially more expensive than the other memory orderings. With careful analysis one can find out what are the minimal guarantees needed for correct operation and select one of the less restrictive memory orderings, giving more leeway to the optimizer.

What's the downside of declare a variable as atomic v.s. a non-atomic variable. For example, what's the downside of std::atomic<int> x v.s. int x? In other words, how much is the overhead of an atomic variable?

Using an atomic variable when a regular variable would suffice limits the number of possible optimizations, because atomic variables impose additional constraints of indivisibility and (possibly) memory ordering.

Using a regular variable when an atomic variable is needed may introduce data races, and that makes the behaviour undefined (§1.10/21):

The execution of a program contains a data race if it contains two conflicting actions in different threads, at least one of which is not atomic, and neither happens before the other. Any such data race results in undefined behavior.

The overhead of an atomic variable is a matter of quality of implementation. Ideally, an atomic variable has zero overhead when you need atomic operations. When you don't need atomic operations, whatever overhead it may have is irrelevant: you just use a regular variable.

Which one has more overhead? An atomic variable, v.s. a normal variable protected by a mutex?

There's no reason for an atomic variable to have more overhead than a normal variable protected by a mutex: worst case scenario, the atomic variable is implemented just like that. But there is a possibility that the atomic variable is lock-free, which would involve less overhead. This property can be ascertained with the functions described in the standard in §29.6.5/7:

bool atomic_is_lock_free(const volatile A *object) noexcept;
bool atomic_is_lock_free(const A *object) noexcept;
bool A::is_lock_free() const volatile noexcept;
bool A::is_lock_free() const noexcept;

Returns: True if the object’s operations are lock-free, false otherwise.

like image 26
R. Martinho Fernandes Avatar answered Oct 21 '22 02:10

R. Martinho Fernandes