int i =1 是原子操作吗?i++是原子操作吗?
int i =1 是原子操作吗?i++是原子操作吗?
1、什么是原子操作
原子(atomic)本意是“不能被进一步分割的最小粒子”,而原子操作(atomic operation)意为“不可被中断的一个或一系列操作”。
- 所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch(切换到另一个线程)。
- 也可以这样理解:如果这个操作所处的层(layer)的更高层不能发现其内部实现与结构,那么这个操作是一个原子(atomic)操作。
- 原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序不可以被打乱,也不可以被切割而只执行其中的一部分。将整个操作视作一个整体是原子性的核心特征。
对于单处理器单核系统来说,只要保证操作指令序列不被打断即可实现原子操作(当然,对于内存的读写操作,需要地址对齐,否则就不是一次的内存读写了,当然也就不是原子操作)。
- 对于简单的原子操作,cpu实现上会提供单条指令,比如INC和XCHG。
- 对于复杂的原子操作,需要包含多条指令。执行过程中,出现上下文切换行为,比如任务切换,中断处理等。这里的行为会影响原子操作的原子性。因此需要自旋锁spinlock[1]来保证操作指令序列不会在执行的中途受干扰。
但是如果对于多处理器或者多核的系统,原子操作的实现除了需要spinlock来保证外,还需要保证不会受到同处理器上其他核,或者其他处理器的影响。当其他核上执行的指令访问的内存空间,与当前原子操作需要访问的内存空间存在冲突时,就会破坏原子操作的正确性。
- 在多核系统中,单个的机器指令就不是原子操作,因为多核系统里是多指令流并行运行的,一个核在执行一个指令时,其他核同时执行的指令有可能操作同一块内存区域,从而出现数据竞争现象。
- 多核系统中的原子操作通常使用内存栅障(memory
barrier)来实现,即一个CPU核在执行原子操作时,其他CPU核必须停止对内存操作或者不对指定的内存进行操作,这样才能避免数据竞争问题。
2、示例:凡有赋值的操作在多线程环境都要加锁
1、给整型变量赋值一个确定的值
int a = 1;
这种指令操作一般是原子的。因为对应着一条计算机指令,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);
return 0;
}
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);
return 0;
}
现在假设a的值是0,有两个线程,每个线程对变量a的值递增1,我们预想的结果应该是2,可实际运行的结果可能是1!分析如下:
//线程1
void thread_func1(){
a++;
}
//线程2
void thread_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.youkuaiyun.com/hellokandy/article/details/87912086
2、https://www.jianshu.com/p/a47b141452ce