这种指令操作一般是原子的。因为对应着一条计算机指令,cpu将立即数1搬运到变量a的内存地址中即可:
int_tmain(int argc, _TCHAR* argv[]){//example 1:int a=1;//a=1 汇编指令 _asm{ mov dword ptr[a],1}printf("%d\n", a);return0;}
2、变量自身增加或者减去一个值
i++
.i++分为三个阶段:在cpu执行时
第一步,先将 count所在内存的值加载到寄存器;第二步,将寄存器的值自增1;第三步,将寄存器中的值写回内存。int_tmain(int argc, _TCHAR* argv[]){//example 2:int a=0;//a++ 汇编指令 _asm{ mov eax, dword ptr[a]//step 1 inc eax//step 2 mov dword ptr[a], eax//step 3}printf("%d\n", a);return0;}
现在假设a的值是0,有两个线程,每个线程对变量a的值递增1,我们预想的结果应该是2,可实际运行的结果可能是1!分析如下:
//线程1voidthread_func1(){ a++;}//线程2voidthread_func2(){ a++;}我们预想的结果是线程1和线程2的三条指令各自执行,最终a的值为2。但是由于操作系统线程调度的不确定性,线程1执行完指令step1、2后,eax寄存器中的值为1。此时操作系统切换到线程2执行,执行指令step1、2、3,此时eax的值变为1;接着操作系统切回线程1继续执行,执行指令step3,得到a的最终结果1。
3、其他示例
把一个变量的值赋值给另外一个变量,或者把一个表达式的值赋值给另外一个变量,如
int a= b;从C/C++语法的级别来看,这是也是一条语句,是原子的;但是从实际执行的二进制指令来看,由于现代计算机CPU架构体系的限制,数据不可以直接从内存搬运到另外一块内存,必须借助寄存器中断,这条语句一般对应两条计算机指令,即将变量b的值搬运到某个寄存器(如eax)中,再从该寄存器搬运到变量a的内存地址:mov eax, dword ptr[b] mov dword ptr[a], eax
既然是两条指令,那么多个线程在执行这两条指令时,某个线程可能会在第一条指令执行完毕后被剥夺CPU时间片,切换到另外一个线程而产生不确定的情况。
参考
1、https://blog.csdn.net/hellokandy/article/details/87912086
2、https://www.jianshu.com/p/a47b141452ce