Here is a piece of code that is DCL (double-checked locking) implemented by ‘Sequentially Consistent Atomics’ semantics in C++. The code is as follows:
std :: atomic <Singleton *> Singleton :: m_instance;
std :: mutex Singleton :: m_mutex;
Singleton * Singleton :: getInstance () {
Singleton * tmp = m_instance.load (); // 3
if (tmp == nullptr) {
std :: lock_guard <std :: mutex> lock (m_mutex);
tmp = m_instance.load ();
if (tmp == nullptr) {
tmp = new Singleton; // 1
m_instance.store (tmp); // 2
}
}
return tmp;
}
I think: '1' includes not only read and write commands, but also call commands, then the call commands may be reordered behind '2'; then '3' may get an unsafe 'tmp' pointer.
So, I want to ask: Is the above code thread-safe?
Yes, instructions can be reordered outside of an if or while. But only if doing so would not change the defined behaviour of the program.
For example a computation such as an add, might be performed outside an if, but it's result only stored inside it.
It is worth noting that if you have undefined behaviour in your program, this can cause extremely unexpected behaviour. Including for the effect of the undefined behaviour to happen before it's cause. https://devblogs.microsoft.com/oldnewthing/20140627-00/?p=633 has some good examples of the kind of transformations modern compilers can do to undefined behaviour.