Just Software Solutions

Using atomics for thread synchronization in C++

Monday, 19 April 2021

In my previous blog post I wrote about spin locks, and how compilers must not move the locking loop above a prior unlock.

After thinking about this done more, I realised that is not something specific to locks — the same issue arises with any two step synchronization between threads.

Consider the following code

std::atomic<bool> ready1{false};
std::atomic<bool> ready2{false};

void thread1(){
  ready1.store(true, std::memory_order_release);
  while(!ready2.load(std::memory_order_acquire)){}
}

void thread2() {
  while(!ready1.load(std::memory_order_acquire)) {}
  ready2.store(true, std::memory_order_release);
}

thread1 sets ready1 to true, then waits for thread2 to set ready2 to true. Meanwhile, thread2 waits for ready1 to be true, then sets ready2 to true.

This is almost identical to the unlock/lock case from the previous blog post, except the waiting thread is just using plain load rather than exchange.

If the compiler moves the wait loop in thread1 above the store then both threads will hang forever. However it cannot do this for the same reason the spinlocks can't deadlock in the previous post: the store has to be visible to the other thread in a finite period if time, so must be issued before the wait loop. https://eel.is/c++draft/intro.multithread#intro.progress-18

An implementation should ensure that the last value (in modification order) assigned by an atomic or synchronization operation will become visible to all other threads in a finite period of time.

If the optimizer moved the store across the loop in thread1, then it could not guarantee that the value became visible to the other thread in a finite period of time. Therefore such an optimization is forbidden.

Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: , , ,
Stumble It! stumbleupon logo | Submit to Reddit reddit logo | Submit to DZone dzone logo

Comment on this post

If you liked this post, why not subscribe to the RSS feed RSS feed or Follow me on Twitter? You can also subscribe to this blog by email using the form on the left.

2 Comments

Please don't use this in production unless you want to burn your CPU. Seriously, don't.

And if you want to use a spinlock, make sure you actually want to use one, and use one that has exponential backoff, or you'll just end up spending more time under contention than with a classic OS mutex.

by Lectem at 08:29:49 on Tuesday, 20 April 2021

Absolutely. This is stripped down code showing just the atomic operations. In real code you would have a lot more happening to avoid burning CPU.

by Anthony Williams at 08:32:40 on Tuesday, 20 April 2021

Add your comment

Your name:

Email address:

Your comment:

Design and Content Copyright © 2005-2021 Just Software Solutions Ltd. All rights reserved. | Privacy Policy