再论int变量赋值的原子性

来源:互联网 发布:淘宝怎么入驻企业店铺 编辑:程序博客网 时间:2024/05/22 10:42
原文链接:再论int变量赋值的原子性<p>http://bbs.chinaunix.net/thread-1805189-1-1.html</p> 
#include <stdio.h>#include <unistd.h>#include <pthread.h>struct STRU{    char a;    int  b;}__attribute__((packed));struct STRU v; void threadfun1(void){    int i = 0;    while(1)    {        if(i%2 == 0)        {            v.b = 0x55555555;        }        else        {            v.b = 0xaaaaaaaa;        }        i++;    }       } void threadfun2(void){   int i;        while(1)    {           i = v.b;        if((i != 0x55555555) && (i != 0xaaaaaaaa))        {               printf("v.b = %x\n", i);        }    }} void main(void){    pthread_t tidFun1;    pthread_t tidFun2;    pthread_create(&tidFun1, NULL, threadfun1, NULL);    pthread_create(&tidFun2, NULL, threadfun2, NULL);    while(1)    {        sleep(5);    }}

可以看到,对变量v.b的一个int赋值被分成了多条汇编语句,在目标机上运行,打印结果为以下多种结果
v.b = 55aaaaaa
v.b = 555555aa
v.b = aa555555
v.b = aaaa5555
......

由此可见,至少在arm9的CPU上,在非内存对齐的情况下,存在一个线程对全局的int变量赋值没有完成而被另一个线程读走,从而导致未知后果的可能性。

如果是在X86上又会如何?

以下是在X86上的汇编代码:

  1. 08048444 <threadfun1>:
  2. 8048444: 55 push %ebp
  3. 8048445: 89 e5 mov %esp,%ebp
  4. 8048447: 83 ec 10 sub $0x10,%esp
  5. 804844a: c7 45 fc 00 00 00 00 movl $0x0,0xfffffffc(%ebp)
  6. 8048451: 8b 45 fc mov 0xfffffffc(%ebp),%eax
  7. 8048454: 83 e0 01 and $0x1,%eax
  8. 8048457: 85 c0 test %eax,%eax
  9. 8048459: 75 0c jne 8048467 <threadfun1+0x23>
  10. 804845b: c7 05 15 97 04 08 55 movl $0x55555555,0x8049715
  11. 8048462: 55 55 55
  12. 8048465: eb 0a jmp 8048471 <threadfun1+0x2d>
  13. 8048467: c7 05 15 97 04 08 aa movl $0xaaaaaaaa,0x8049715
  14. 804846e: aa aa aa
  15. 8048471: 83 45 fc 01 addl $0x1,0xfffffffc(%ebp)
  16. 8048475: eb da jmp 8048451 <threadfun1+0xd>
复制代码


由上看到,X86对这种字节对齐的int变量也是只用了一条movl语句进行赋值,所以不会存在赋值到一半被另一个线程读走的情况,通过运行实验程序也证明了这个问题。

最后,虽然题目是“再论int变量赋值的原子性”,但如果其内容能达到前一帖子的百分之一二有用,我就心满意足了

0 0
原创粉丝点击