免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: mingjwan
打印 上一主题 下一主题

对int变量的赋值是原子操作吗? [复制链接]

论坛徽章:
2
亥猪
日期:2014-03-19 16:36:35午马
日期:2014-11-23 23:48:46
111 [报告]
发表于 2006-08-11 15:44 |只看该作者
原帖由 whyglinux 于 2006-8-11 15:04 发表


一个 C 语句通常对应着一条或者多条指令。如果对应着多条指令,那么这个赋值操作就有可能从中间被中断,这时可以说赋值操作不是原子的。这是一种从指令集角度上的理解。

还可以有另外一种理解,即从赋值操 ...


实际效果是什么效果?什么是原子?
原子的定义就是不可被打断的操作/实物
物理上的定义就是不可再分的物体,虽然这个定义被找到更小的粒子而模糊。
而操作上的原子 它的意义也就是不可再分的操作。可以被中断了,怎么能说是原子呢?


  1. int b, i;
  2. main()
  3. {
  4.   ....
  5.     pthread_create(&thread, NULL, (void *(*)(void *))incCount1, (void *)r);
  6.     pthread_create(&thread, NULL, (void *(*)(void *))incCount2, (void *)r);
  7.    ....
  8. }
  9. void *incCount1( int id )
  10. {   
  11.     while(1){
  12.         i = 10;
  13.     }
  14. }

  15. void *incCount2( int id )
  16. {   
  17.     while(1){
  18.         i = 50;
  19.         b = i;
  20.         if (b!=i)
  21.         {   
  22.             printf("crashed\n");
  23.             exit(1);
  24.         }
  25.     }
  26. }
复制代码

这段程序很简单,主要看b被赋值后是否是i。当然i = 50;b = i; if 这3条语句任何时候都有可能被打断。
看asm,主要就是两个循环,所以踢掉了不必要信息。

  1. incCount1:
  2.         ...
  3. .L24:
  4.         movl    $10, i
  5.         jmp     .L24
  6.         ...
复制代码

  1. incCount2:
  2.         ...
  3. .L28:
  4.         movl    $50, i          #1
  5.         movl    i, %eax       #2
  6.         movl    %eax, b      #3
  7.         movl    b, %eax      #4
  8.         cmpl    i, %eax       #5
  9.         je      .L28
  10.         ...
复制代码


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 却发生了。

看来不少人对"原子性"这个概念的理解问题很大啊

论坛徽章:
0
112 [报告]
发表于 2006-08-11 15:44 |只看该作者
对于中断,CPU会有现场保护的
不过有部分单片机似乎没有现场保护

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
113 [报告]
发表于 2006-08-11 15:46 |只看该作者
原帖由 whyglinux 于 2006-8-11 15:04 发表

看atomic_t的定义,就定义为一个整数。


第一.

我这里说volatile,是因为 whyglinux大人说 atomic_t定义为一个整数..我提出了反驳..

第二.

多进程操作共享内存,哪怕就是一个int 也要加信号量,具体的细节可以去看操作系统的书..
而且如果我没记错的话,stevens在他的Unix网络编程上 也是给共享内存所操作的加信号量,或者互斥锁是非常明确的.


第三.

两条指令首先就不是原子的了..
说int 赋值语句翻译成汇编语句为两条指令.  并且该变量为多进程或多线程的全局变量,那么一定存在进程被切换的情况。不能保证原子.

以上是我的观点.

论坛徽章:
2
亥猪
日期:2014-03-19 16:36:35午马
日期:2014-11-23 23:48:46
114 [报告]
发表于 2006-08-11 15:54 |只看该作者
原帖由 思一克 于 2006-8-11 13:27 发表
TO gvim,

一个
i = j; 语句是这样的

0x08048379 <func1+3>:   mov    0x8049584,%eax
0x0804837e <func1+8>:   mov    %eax,0x8049588

在多THREAD的程序中原子性有问题吗?两个mov之间中 ...


关键在于,i = j ,你不能保证执行之后 i 就一定等于 j,例子在上面给出了。
而原子性的作用就在于此:只要你执行了这个操作,保证就是你要的结果。

论坛徽章:
0
115 [报告]
发表于 2006-08-11 15:57 |只看该作者
原子性就是从使用者角度不用加琐来保证数据的一致性。
至于中间是否有中断打断不用管。

谈系统调用的原子性就是这含义。比如write,有数百上千汇编指令,但在许多时候都可以说是原子的。

论坛徽章:
0
116 [报告]
发表于 2006-08-11 15:58 |只看该作者
原帖由 gvim 于 2006-8-11 15:54 发表


关键在于,i = j ,你不能保证执行之后 i 就一定等于 j,例子在上面给出了。
而原子性的作用就在于此:只要你执行了这个操作,保证就是你要的结果。



i = j; 什么时候下不是原子的?

要执行什么操作来保证其原子性?

论坛徽章:
0
117 [报告]
发表于 2006-08-11 15:59 |只看该作者
原帖由 思一克 于 2006-8-11 15:57 发表
原子性就是从使用者角度不用加琐来保证数据的一致性。
至于中间是否有中断打断不用管。

谈系统调用的原子性就是这含义。比如write,有数百上千汇编指令,但在许多时候都可以说是原子的。


对,我觉得原子的含义就是这样的

论坛徽章:
0
118 [报告]
发表于 2006-08-11 16:01 |只看该作者
原帖由 gvim 于 2006-8-11 15:54 发表


关键在于,i = j ,你不能保证执行之后 i 就一定等于 j,例子在上面给出了。
而原子性的作用就在于此:只要你执行了这个操作,保证就是你要的结果。

就你前面的程序来说吧,假设在每一个赋值语句两边都加了锁。用你的观点,现在都是原子的了对吧。

但是后边的 if 一样可能成立。因为中断会发生在任何时候。对于下一条语句来说,前面的结果总是不可靠的。所以我说从效果上来说,原子与否其实都一样。

当然如果你从理论上深究,那确实不是理论上的原子性。但理论总是要拿来用的

[ 本帖最后由 isjfk 于 2006-8-11 16:03 编辑 ]

论坛徽章:
0
119 [报告]
发表于 2006-08-11 16:04 |只看该作者
原帖由 isjfk 于 2006-8-11 16:01 发表

就你前面的程序来说吧,假设在每一个赋值语句两边都加了锁。用你的观点,现在都是原子的了对吧。

但是后边的 if 一样可能成立。因为中断会发生在任何时候。对于下一条语句来说,前面的结果总是不可靠的。所以 ...


打断一下,你所说的加锁是怎么个加锁法?

论坛徽章:
2
亥猪
日期:2014-03-19 16:36:35午马
日期:2014-11-23 23:48:46
120 [报告]
发表于 2006-08-11 16:09 |只看该作者
原帖由 思一克 于 2006-8-11 15:57 发表
原子性就是从使用者角度不用加琐来保证数据的一致性。
至于中间是否有中断打断不用管。

谈系统调用的原子性就是这含义。比如write,有数百上千汇编指令,但在许多时候都可以说是原子的。


呵,LZ的问题是"对int变量的赋值是原子操作吗"。我的回答是“不是”。
从字节赋值的角度看,我并不清楚是否大部分常见的赋值都是32位一次的(或者在非对其的情况下需要两次赋值),所以我没有给出任何答案。在ARM中,short, char等的赋值操作并不像int那样简单。
从下面isjfk 开始有部分争论存在于"多条语句的赋值是否仍然是原子的",基于此我发表了自己的见解。

末了,既然要往偏里掰,我也就不接招了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP