It has been mentioned by several, for example here c++ what happens when in one thread write and in second read the same object? (is it safe?) that if two threads are operating on the same variable without atomics and lock, reading the variable can return neither the old value nor the new value.
Correct. Undefined behavior is undefined.
I don't understand why this can happen and I cannot find an example such things happen, I think load and store is always one single instruction which will not be interrupted, then why can this happen?
Because undefined behavior is undefined. There is no requirement that you be able to think of any way it can go wrong. Do not ever think that because you can't think of some way something can break, that means it can't break.
For example, say there's a function that has an unsynchronized read in it. The compiler could conclude that therefore this function can never be called. If it's the only function that could modify a variable, then the compiler could omit reads to that variable. For example:
int j = 12;
// This is the only code that modifies j
int q = some_variable_another_thread_is_writing;
j = 0;
// other code
if (j != 12) important_function();
Since the only code that modifies j
reads a variable another thread is writing, the compiler is free to assume that code will never execute, thus j
will always be 12, and thus the test of j
and the call to important_function
can be optimized out. Ouch.
Here's another example:
if (some_function()) j = 0;
else j = 1;
If the implementation thinks that some_function
will almost always return true
and can prove some_function
cannot access j
, it is perfectly legal for it to optimize this to:
j = 0;
if (!some_function()) j++;
This will cause your code to break horribly if other threads mess with j
without a lock or j
is not a type defined to be atomic.
And do not ever think that some compiler optimization, though legal, will never happen. That has burned people over and over again as compilers get smarter.