Originally posted by milkylainen
View Post
int a;
a++;
I am not expert on x86 assembly, but I expect it would translate to the following machine code:
move [address of a], eax
add eax,1
move eax,[address of a]
In other words, you usually fetch the content to the cpu register, do your work and then write it back to the memory. Any other processor or thread might kick in and modify value of a in the mean between the three instructions. So, there is no atomicity here.
char c;
c=0;
Plain assignment of 1 byte value is atomic. I would guess, that assignment of properly aligned int or even double might be atomic on most 64-bit architectures, e.g. if two threads write to the same variable at the same moment, there will be one or other value, but not few bytes of each. But we are on the thin ice here. If something shall be atomic, you shall use the proper synchronization primitives. What if the compiler and its optimizer decide that the variable will not get place in memory but stays only in a register, and is written to the memory only at the end of our very long function? So another thread might try to read in-progress-values, but it will see nothing until the end of our very long function when the compiler decided to write the value from the register back to the memory. And even worse: you might assign some value to one variable and some value to another variable. If you will be looking from other thread or processor on the two values, you would expect that new value of the first variable will appear first and the value of the second variable as the second one. However, there are no such guarantees. You might see it in any order. The compiler is the first one who might reorder their writes. Even if it keeps the order, there might be other "trolls" around. We might suspect speculative execution to be free to change the order of instructions. Luckily, there is ROB stage at the end of cpu pipeline that orders all the writes to happen exactly as they are written in the code. So, the speculative execution is probably not guilty. But what about caches? The two variables might be in the different cache lines. Are they written back to the main memory in the correct order? As far as I remember, I would guess that current multiprocessor systems are using special cache protocol to keep caches in consistent state. If one processor is writing a cache line, it is invalidated in all the caches of all other processors. As the result, you will probably never see the second write jump before the first one.
Did I got your question right and are the things above giving a little more light on the problem? In short, unless you are multithreading expert, always use locks, atomics, etc. when using data shared between two threads. For example, appending and removing from std::list from two threads concurrently is likely to result in broken list, and very hard to debug magical application crashes.
Leave a comment: