c++, c++11, std::atomic member functions
I am trying to use std::atomic library.
std::atomic<int> x
vs int x
? In other words, how much is the overhead of an atomic variable? Here is the reference to my quesitons. http://en.cppreference.com/w/cpp/atomic/atomic
Not an expert, but I'll try:
int
) contain additional operations such as fetch_add
. Non-specialized forms (user defined types) will not contain these. 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
. load
. int
in the way you would use std::atomic_int
. 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
. 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:
What's the difference (if there is any) between following functions?
operator=
stores a value into an atomic object (public member function) vs 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 vs a non-atomic variable. For example, what's the downside of std::atomic<int> x
vs 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, vs 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.
I'm not an expert on this stuff, but if I understand correctly the non-specialized operations in your reference do one thing atomically, load, store, replace, etc.
The specialized function do two things atomically, that is they modify and then return an atomic object in such a way that both operations happen before any other thread could mess with them.
链接地址: http://www.djcxy.com/p/26942.html上一篇: C ++