C语言的赋值++是否为原子操作
2013-11-03 22:14
609 查看
相关概念:
时钟周期、总线周期和指令周期
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 plaincopy
#include <stdio.h>
void fun1()
{
volatile int m;
volatile int n;
m = 99;
n = m;
}
void fun2()
{
volatile int n = 10;
n++;
}
int main(int argc, char** argv)
{
fun();
return 0;
}
汇编:
gcc -S main.c
查看fun1相关的指令:
[plain]
view plaincopy
pushq %rbp
movq %rsp, %rbp
movl $99, -4(%rbp)
movl -4(%rbp), %eax
movl %eax, -8(%rbp)
leave
fun2相关指令:
[plain]
view plaincopy
pushq %rbp
movq %rsp, %rbp
movl $10, -4(%rbp)
leaq -4(%rbp), %rax
incl (%rax)
movl %eax, -4(%rbp)
leave
可以看到,n = m为两条指令:
movl -4(%rbp), %eax
movl %eax, -8(%rbp)
n++三条指令:
leaq -4(%rbp), %rax
incl (%rax)
movl %eax, -4(%rbp)
都是多条指令,所以,不是原子操作。
总结:
原子操作和硬件实现、编译器实现都紧密相关,因此,单纯的在高级语言的层次讨论原子操作,没有太大的意义。
但是在操作系统中还是会介绍有这个概念的讲解,到时候留心分析
时钟周期、总线周期和指令周期
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 plaincopy
#include <stdio.h>
void fun1()
{
volatile int m;
volatile int n;
m = 99;
n = m;
}
void fun2()
{
volatile int n = 10;
n++;
}
int main(int argc, char** argv)
{
fun();
return 0;
}
汇编:
gcc -S main.c
查看fun1相关的指令:
[plain]
view plaincopy
pushq %rbp
movq %rsp, %rbp
movl $99, -4(%rbp)
movl -4(%rbp), %eax
movl %eax, -8(%rbp)
leave
fun2相关指令:
[plain]
view plaincopy
pushq %rbp
movq %rsp, %rbp
movl $10, -4(%rbp)
leaq -4(%rbp), %rax
incl (%rax)
movl %eax, -4(%rbp)
leave
可以看到,n = m为两条指令:
movl -4(%rbp), %eax
movl %eax, -8(%rbp)
n++三条指令:
leaq -4(%rbp), %rax
incl (%rax)
movl %eax, -4(%rbp)
都是多条指令,所以,不是原子操作。
总结:
原子操作和硬件实现、编译器实现都紧密相关,因此,单纯的在高级语言的层次讨论原子操作,没有太大的意义。
但是在操作系统中还是会介绍有这个概念的讲解,到时候留心分析
相关文章推荐
- 面试题【1】:i++是否原子操作?并解释为什么?
- C语言的赋值语句是不是原子操作?
- i++是否原子操作?并解释为什么?
- C语言文件操作 fopen, fclose, mkdir(打开关闭文件,建文件夹,判断文件是否存在可读或可写)
- i++和++i是否为原子操作
- C语言文件操作 fopen, fclose, mkdir(打开关闭文件,建文件夹,判断文件是否存在可读或可写)
- i++是否原子操作
- C语言赋值语句是不是原子操作?
- Redis研究(七)—如何判断set/get是否为原子操作
- i++ 是否为原子操作 和 Java中的volatile关键字
- C#读写数据是否为原子操作
- 面试题【1】:i++是否原子操作?并解释为什么?
- 顺序表原子操作的实现(C语言)
- C#读写内置类型的数据时是否原子操作
- i++是否原子操作?并解释为什么?
- 面试题【1】:i++是否原子操作?并解释为什么?
- C语言文件操作 fopen, fclose, mkdir(打开关闭文件,建文件夹,判断文件是否存在可读或可写)
- i++是否原子操作?并解释为什么?
- C语言文件操作 fopen, fclose, mkdir(打开关闭文件,建文件夹,判断文件是否存在可读或可写)
- 【讨论】++int是否为原子操作