I am trying to get familiar with the new memory ordering concepts of c++11 and believed I actully had a quite good grasp on them, until I stumbled upon this implementation of a spin lock:
#include <atomic>
namespace JayZ
{
namespace Tools
{
class SpinLock
{
private:
std::atomic_flag spin_lock;
public:
inline SpinLock( void ) : atomic_flag( ATOMIC_FLAG_INIT ) {}
inline void lock( void )
{
while( spin_lock.test_and_set( std::memory_order_acquire ) )
;
}
inline void unlock( void )
{
lock.clear( std::memory_order_release );
}
};
}
}
It is e.g. equivalently mentioned at http://en.cppreference.com/w/cpp/atomic/atomic_flag
and also in the book "Concurrency in Action". I also found it someplace here at SO.
But I just don't understand why it would work!
Imagine thread 1 calls lock() and test_and_set() returns 0 as the old value --> thread 1 has acquired the lock.
But then thread 2 comes along and tries the same. Now since there has occurred no "store synchronization" (release,seq_cst_acq_rel) thread 1's store to spin_lock should be of type relaxed.
But from this follows that it cannot imao be synchronized with thread 2's read of spin_lock. This should make it possible for thread 2 to read the value 0 from spin_lock and thus acquire the lock as well.
Where is my mistake?