C语言的赋值++是否为原子操作

相关概念:
时钟周期、总线周期和指令周期
1.时钟周期:微处理器执行指令的最小时间单位,又称T状态。它通常与微机的主频有关。
2.总线周期:CPU对存储器或I/O端口完成一次读/写操作所需的时间。如8086微处理器的基本总线周期由四个时钟周期T1~T4组成,80486微处理器的基本总线周期由T1和T2两个时钟周期组成。当外设速度较慢时,可插入等待周期Tw。
3.指令周期:CPU执行一条指令所需要的时间。 指令周期由若干个总线周期组成,不同指令执行的时间不同。同一功能的指令,在寻址方式不同时,所需要的时间也不同。

总线操作周期:微机系统各部件之间的信息交换是通过总线操作周期完成的,一个总线周期通常分为以下四个阶段。
1.总线请求和仲裁阶段:当有多个模块提出总线请求时,必须由仲裁机构仲裁,确定将总线的使用权分配给哪个模块。
2.寻址阶段:取得总线使用权的模块,经总线发出本次要访问的存储器或I/O端口的地址和有关命令。
3.传送数据阶段:主模块(指取得总线控制权的模块)与其他模块之间进行数据的传送。
4.结束阶段:主模块将有关信息从总线上撤除,主模块交出对总线的控制权。

CPU最小的执行单元是指令,一个指令周期可能包括多个总线周期。
我们可以得到:
1. 在单处理器下,一个操作只包括一个cpu指令可以保证是原子操作。如果一个操作包含多个cpu指令不是原子操作。
2. 在多处理器下,由于一个cpu指令周期可能包含多个总线周期,就有可能出现其他处理器在一个指令执行期间访问了其相关的状态。因此,多处理器下,指令执行期间还必须锁总线,才能保证CPU指令的原子性


我们看下C语言的赋值和++操作

代码main.c:

[cpp] view plain copy
  1. #include <stdio.h>  
  2.   
  3. void fun1()  
  4. {  
  5.         volatile int m;  
  6.         volatile int n;  
  7.         m = 99;  
  8.         n = m;  
  9. }  
  10.   
  11. void fun2()  
  12. {  
  13.         volatile int n = 10;  
  14.         n++;  
  15. }  
  16.   
  17. int main(int argc, char** argv)  
  18. {  
  19.         fun();  
  20.   
  21.         return 0;  
  22. }  
汇编:
gcc -S main.c
查看fun1相关的指令:
[plain] view plain copy
  1. pushq   %rbp  
  2.       movq    %rsp, %rbp  
  3.       movl    $99, -4(%rbp)  
  4.       movl    -4(%rbp), %eax  
  5.       movl    %eax, -8(%rbp)  
  6.       leave  
fun2相关指令:
[plain] view plain copy
  1. pushq   %rbp  
  2. movq    %rsp, %rbp  
  3. movl    $10, -4(%rbp)  
  4. leaq    -4(%rbp), %rax  
  5. incl    (%rax)  
  6. movl    %eax, -4(%rbp)  
  7. leave  

可以看到,n = m为两条指令:
        movl    -4(%rbp), %eax
        movl    %eax, -8(%rbp)

n++三条指令:
         leaq    -4(%rbp), %rax
         incl    (%rax)  
         movl    %eax, -4(%rbp)
都是多条指令,所以,不是原子操作。

总结:

原子操作和硬件实现、编译器实现都紧密相关,因此,单纯的在高级语言的层次讨论原子操作,没有太大的意义。

但是在操作系统中还是会介绍有这个概念的讲解,到时候留心分析

你可能感兴趣的:(原子操作)