私は c++11 の新しいメモリ順序付けの概念に慣れようとしていますが、このスピン ロックの実装に出くわすまでは、実際にはかなりよく理解していると思っていました。
#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 );
}
};
}
}
たとえば、http://en.cppreference.com/w/cpp/atomic/atomic_flag
や書籍「Concurrency in Action」でも同様に言及されています。ここSOのどこかでも見つけました。
しかし、なぜそれが機能するのかわかりません!
スレッド 1 が lock() を呼び出し、test_and_set() が古い値として 0 を返すと想像してください --> スレッド 1 がロックを取得しました。
しかし、その後、スレッド 2 がやってきて、同じことを試みます。ここで、「ストア同期」(release,seq_cst_acq_rel) が発生していないため、スレッド 1 の spin_lock へのストアは、relaxed 型である必要があります。
しかし、このことから、スレッド 2 の spin_lock の読み取りと同期できないことがわかります。これにより、スレッド 2 が spin_lock から値 0 を読み取り、ロックも取得できるようになります。
私の間違いはどこですか?