免费注册 查看新帖 |

Chinaunix

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

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

论坛徽章:
0
41 [报告]
发表于 2006-08-09 15:03 |只看该作者
flw程序改动版。TEST1, TEST2可以选择。

可以看到原子性。



  1. # include <stdio.h>
  2. # include <stdlib.h>
  3. # include <pthread.h>
  4. # include <unistd.h>

  5. int runFlag = 1;
  6. int count = 0;

  7. #define TEST2

  8. void *incCount( int id );

  9. int main( void )
  10. {
  11.     pthread_t thread;
  12.     int i;
  13.     int ret;

  14.     for( i=0; i<6; i++ ){
  15.         ret = pthread_create( &thread, NULL, (void *(*)(void *))incCount, (void *)i );
  16.         if ( ret != 0 ){
  17.             perror( "pthread_create" );
  18.             exit(-1);
  19.         }
  20.     }

  21.     printf( "Wait 5 seconds...\n" );
  22.     sleep(5);
  23.     printf( "Modify runFlag, stop all work thread.\n" );
  24.     runFlag = 0;
  25.     sleep(1);
  26.     printf( "count = [%d]\n", count );
  27.     printf( "Done.\n" );

  28.     return 0;
  29. }


  30. void *incCount( int id )
  31. {
  32.     int i;
  33.     unsigned int k, v;
  34.     id++;
  35.     k = 0x11111111*id;
  36.     printf( "Hello, I am pthread %d\n", id );
  37.     while(runFlag){
  38.         for( i=0; i<10000; i++ ){
  39.             count = k;

  40. #ifdef TEST1
  41.             v = count;
  42.             if((v & 0x0000ffff) != (v >> 16)) {
  43.                 printf("%p %p\n", v, count);

  44.             }
  45. #endif
  46. #ifdef TEST2
  47.            if(count != k)
  48.                 printf("%p %p\n", k, count);
  49. #endif
  50.         }
  51.     }

  52.     printf( "[%d] Done.\n", id );
  53.     return NULL;
  54. }

复制代码

论坛徽章:
0
42 [报告]
发表于 2006-08-09 16:18 |只看该作者
原帖由 思一克 于 2006-8-9 14:34 发表
不用加。
可以第一个THREAD 将count 设为0x11111111
第二个设22222222,
。。。
第6个设66666666
循环10000次
检查数值,如果数值为这六个数之一,就是原子的,可以保持沉默。
否则打印出来信息,就不是原 ...

这个思路有问题。很可能中间的赋值失败被后面的成功的赋值冲掉。

测试赋值的原子性应该用一种可以把错误放大的方法

论坛徽章:
0
43 [报告]
发表于 2006-08-09 16:21 |只看该作者
这有什么好讨论的.
从原理上讲就是原子性的.
即使机器语言有多条指令, 即使中间被打断, 也不影响其原子性.
对于mips 机器也是原子性的, 中间被打断时, 数据还在寄存器中, 还没复制到变量的地址中, 数据复制到变量的地址中只需要一条机器码.

论坛徽章:
0
44 [报告]
发表于 2006-08-09 16:27 |只看该作者
to connet,

同意。本来就不是问题。但不是有如此大的误解,才来证明吗

论坛徽章:
0
45 [报告]
发表于 2006-08-09 16:36 |只看该作者
to connet,

不同意。本来就不是问题。但不是有如此大的误解,才来证明吗。不是所有的平台都保证整形最终的赋值是一条机器指令

论坛徽章:
0
46 [报告]
发表于 2006-08-09 16:39 |只看该作者
to jsjfk,

那你说一个平台(不要说单片呀)的列外并将反汇编的代码贴出来。

论坛徽章:
0
47 [报告]
发表于 2006-08-09 17:28 |只看该作者
世界上的正在使用的 CPU 体系结构起码几百种,我能找到所有的都试一遍?我可以证明 linux 源代码中至少有两种 CPU 的 atomic_set 不是简单的 int 赋值而是加了锁。这两种平台我都没有条件测试,虽然不能作为证据,但起码有一定的参考价值。
http://lxr.linux.no/source/include/asm-parisc/atomic.h
http://lxr.linux.no/source/arch/sparc/lib/atomic32.c

这个世界上正在使用的 CPU 不只是 x86,除非有人能够拿出证据证明所有的 CPU 体系结构上的 C 编译器编译出来的整形赋值其机器码都是原子操作,否则就不能作这样的假设。不要拿“常用的 CPU 都是原子的”作反驳,lz 并没有把问题局限在“常用的 CPU”上面。或许对你来说 x86 就代表整个世界,但是对于很多用单片机工作的人来说,51、AVR、PIC 远远要比 x86 亲切得多。我为什么不能用单片机举例?C 又不是 x86 的私有玩物

论坛徽章:
0
48 [报告]
发表于 2006-08-09 19:25 |只看该作者
原帖由 mingjwan 于 2006-8-4 09:32 发表
请问对int变量的赋值是原子操作吗?
会不会出现一个线程赋了两个字节,另一个线程来读取数据的情况呢?


对 int 变量的赋值是否是原子操作与使用的计算机的结构体系有关,同时也与此变量的内存对齐情况有关。

一般的体系结构中都能把一个 int 大小的数据作为一个整体进行处理,也就是说用一条指令完成。对于这样的系统,对 int 变量的赋值是否是原子操作还取决于此数据在内存中是否已经对齐:如果变量是内存对齐的话,那么就有可能是原子操作;如果非内存对齐,那么一个 int 数据要分至少两次才能完成,就不是原子操作了。

但是也有的结构体系不是这样的,如 zu_xf 在上面提到的情况,一个 int 数据要拆分为几部分分别处理,对于这样的体系结构,对 int 赋值就不是原子操作了。

如果不是原子操作,就有可能“出现一个线程赋了两个字节,另一个线程来读取数据的情况”。

论坛徽章:
0
49 [报告]
发表于 2006-08-09 19:29 |只看该作者
NB,看你的大脑也没有闲着…………………………

论坛徽章:
0
50 [报告]
发表于 2006-08-09 22:55 |只看该作者
如果不是原子操作,就有可能“出现一个线程赋了两个字节,另一个线程来读取数据的情况”。

这个能不能解释一下(单CPU),难道一条指令执行了一半.换别的指令(因为要运行其它线程)?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP