- 论坛徽章:
- 2
|
原帖由 whyglinux 于 2006-8-11 15:04 发表
一个 C 语句通常对应着一条或者多条指令。如果对应着多条指令,那么这个赋值操作就有可能从中间被中断,这时可以说赋值操作不是原子的。这是一种从指令集角度上的理解。
还可以有另外一种理解,即从赋值操 ...
实际效果是什么效果?什么是原子?
原子的定义就是不可被打断的操作/实物
物理上的定义就是不可再分的物体,虽然这个定义被找到更小的粒子而模糊。
而操作上的原子 它的意义也就是不可再分的操作。可以被中断了,怎么能说是原子呢?
- int b, i;
- main()
- {
- ....
- pthread_create(&thread, NULL, (void *(*)(void *))incCount1, (void *)r);
- pthread_create(&thread, NULL, (void *(*)(void *))incCount2, (void *)r);
- ....
- }
- void *incCount1( int id )
- {
- while(1){
- i = 10;
- }
- }
- void *incCount2( int id )
- {
- while(1){
- i = 50;
- b = i;
- if (b!=i)
- {
- printf("crashed\n");
- exit(1);
- }
- }
- }
复制代码
这段程序很简单,主要看b被赋值后是否是i。当然i = 50;b = i; if 这3条语句任何时候都有可能被打断。
看asm,主要就是两个循环,所以踢掉了不必要信息。
- incCount1:
- ...
- .L24:
- movl $10, i
- jmp .L24
- ...
复制代码
- incCount2:
- ...
- .L28:
- movl $50, i #1
- movl i, %eax #2
- movl %eax, b #3
- movl b, %eax #4
- cmpl i, %eax #5
- je .L28
- ...
复制代码
incCount1地循环里只有movl $10, i 一句,是原子的。所以可以简单的认为只要运行了incCount1,i 的值必然变成10.
incCount2的循环里有5句,每两句之间标记为@12, @23, @34, @45 。
我们需要比较的是b = i 之后 b =? i,简单起见假设incCount2的一次循环中只可能发生一次线程切换(如果发生2次以上的话,效果更佳)
#2和#3是b = i的代码。
那么:
如果切换发生在#1之前,再换到incCount2的时候,i = 10,继续执行#1,i = 50,由于上面的假设,则后面的 if 不成立,即 b == i。
如果切换发生在@12,那么i = 10,由于上面的假设,后面的 if 也不会成立。
如果切换发生在@23,那么i = 10,由于%eax被自动保存,那么%eax = b = 50,则后面的 if 成立。
如果切换发生在@34,那么i = 10,b = 50,则后面的 if 成立。
如果切换发生在@45,那么i = 10,b = 50,则后面的 if 成立。
可以看到在@23, @34, @45 三处地方发生切换的话,b 是不等于 i 的。
发生在@34、@45处的切换说明了不一致性的存在。
中断既然可以发生在@34、@45处,为什么不能发生在@23处?
发生在@23处的切换说明了b = i 的赋值并不是不可打断的。
>>>如果写指令只有一条的话,赋值操作是原子的
在可以使 if 不成立的 3 处地方,只有一条对变量的写指令,即movl %eax, b。按照你的说法就是原子了,但是 b != i 却发生了。
看来不少人对"原子性"这个概念的理解问题很大啊 |
|