Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::atomic | compare_exchange_weak vs. compare_exchange_strong

I'm unsure if it's me not understanding or the documentation isn't clearly formulated.

The following excerpt has been taken from the newest draft (N3126, section 29.6):

bool atomic_compare_exchange_weak(volatile A* object, C * expected, C desired); bool atomic_compare_exchange_weak(A* object, C * expected, C desired); bool atomic_compare_exchange_strong(volatile A* object, C * expected, C desired); bool atomic_compare_exchange_strong(A* object, C * expected, C desired); bool atomic_compare_exchange_weak_explicit(volatile A* object, C * expected, C desired, memory_order success, memory_order failure); bool atomic_compare_exchange_weak_explicit(A* object, C * expected, C desired, memory_order success, memory_order failure); bool atomic_compare_exchange_strong_explicit(volatile A* object, C * expected, C desired, memory_order success, memory_order failure); bool atomic_compare_exchange_strong_explicit(A* object, C * expected, C desired, memory_order success, memory_order failure); bool A::compare_exchange_weak(C & expected, C desired, memory_order success, memory_order failure) volatile; bool A::compare_exchange_weak(C & expected, C desired, memory_order success, memory_order failure); bool A::compare_exchange_strong(C & expected, C desired, memory_order success, memory_order failure) volatile; bool A::compare_exchange_strong(C & expected, C desired, memory_order success, memory_order failure); bool A::compare_exchange_weak(C & expected, C desired, memory_order order = memory_order_seq_cst) volatile; bool A::compare_exchange_weak(C & expected, C desired, memory_order order = memory_order_seq_cst); bool A::compare_exchange_strong(C & expected, C desired, memory_order order = memory_order_seq_cst) volatile; bool A::compare_exchange_strong(C & expected, C desired, memory_order order = memory_order_seq_cst); 

Remark: The weak compare-and-exchange operations may fail spuriously, that is, return false while leaving the contents of memory pointed to by expected before the operation is the same that same as that of the object and the same as that of expected after the operation. [ Note: This spurious failure enables implementation of compare-and-exchange on a broader class of machines, e.g., loadlocked store-conditional machines. A consequence of spurious failure is that nearly all uses of weak compare-and-exchange will be in a loop.

So, what does this mean?

Firstly, it 'may' fail spuriously?! Why would it fail? And how do they define 'may'?

Secondly, I still have no idea what's the difference between the functions with "_strong" and "_weak" suffix. Could someone explain the difference?

EDIT: That's what I've found in libstdc++-implementation (atomic_0.h):

bool compare_exchange_weak(     __integral_type& __i1,     __integral_type __i2,     memory_order __m1,     memory_order __m2 ) {     __glibcxx_assert(__m2 != memory_order_release);     __glibcxx_assert(__m2 != memory_order_acq_rel);     __glibcxx_assert(__m2 <= __m1);     return _ATOMIC_CMPEXCHNG_(this, &__i1, __i2, __m1); }  bool compare_exchange_strong(     __integral_type& __i1,     __integral_type __i2,     memory_order __m1,     memory_order __m2 ) {     __glibcxx_assert(__m2 != memory_order_release);     __glibcxx_assert(__m2 != memory_order_acq_rel);     __glibcxx_assert(__m2 <= __m1);     return _ATOMIC_CMPEXCHNG_(this, &__i1, __i2, __m1); } 
like image 326
0xbadf00d Avatar asked Feb 09 '11 12:02

0xbadf00d


People also ask

What is Compare_exchange_strong?

std::atomic::compare_exchange_strongCompares the contents of the contained value with expected : - if true, it replaces the contained value with val (like store ). - if false, it replaces expected with the contained value .

Is std :: swap Atomic?

It is not atomic. Atomic operations are not cheap and 99% of the time you do not need the atomicity. There are (IIRC) some other means to get atomic operations but std::swap() is not one of them.

What is atomic compare exchange?

In computer science, compare-and-swap (CAS) is an atomic instruction used in multithreading to achieve synchronization. It compares the contents of a memory location with a given value and, only if they are the same, modifies the contents of that memory location to a new given value.


1 Answers

The note gives a clue, referring to LL/SC architectures. From the Wikipedia article:

If any updates have occurred, the store-conditional is guaranteed to fail, even if the value read by the load-link has since been restored. As such, an LL/SC pair is stronger than a read followed by a compare-and-swap (CAS), which will not detect updates if the old value has been restored (see ABA problem).

Real implementations of LL/SC do not always succeed if there are no concurrent updates to the memory location in question. Any exceptional events between the two operations, such as a context switch, another load-link, or even (on many platforms) another load or store operation, will cause the store-conditional to spuriously fail.

On LL/SC chips the compare_exchange will be implemented in terms of LL/SC, which can spuriously fail, so compare_exchange_strong needs extra overhead to retry in the case of failure. Providing both compare_exchange_strong and compare_exchange_weak allows the programmer to decide whether they want the library to handle spurious failures (in which case they'd use compare_exchange_strong) or if they want to handle it in their own code (in which case they'd use compare_exchange_weak)

like image 110
Jonathan Wakely Avatar answered Oct 05 '22 14:10

Jonathan Wakely