看一个很简单的C程序:

1
2
3
4
5
6
7
8
int n = 0;
int
main()
{
    while(!n)
        ;
    return 0;
}

  很明显,这是一个死循环,因为n的值总为0。再看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int n = 0;
void *foo(void*);
int
main()
{
    pthread_t pth_id;
    pthread_create(&pth_id, NULL, foo, NULL);
    while(!n)
        ;
    pthread_join(pth_id, NULL);
    return 0;
}
 
void *foo(void* arg)
{
    printf("n: %d\n", n);
    sleep(5);
    ++n;
    printf("++n: %d\n", n);
    return NULL;
}

  这是一个使用pthread库的多线程程序。主线程在以函数foo创建一个线程后,进入while循环。线程函数foo中,首先打印全局变量n的值,沉睡约5秒钟后,修改n,最后再次打印n值,然后该线程退出(等待主线程join)。
  正常情况下,在终端编译执行该多线程程序,首先打印n(0),5秒后再次打印n(1),然后该进程正常退出。
  但,如果使用gcc编译此程序时,使用优化选项(比如-O1),再执行此程序。首先打印n(0),5秒后再次打印n(1),然后呢,然后就死循环啦!
  为什么呢?看一看汇编代码就知道了,使用gcc -O1 -S命令编译第一段代码,得到的汇编码:

1
2
3
4
5
6
7
main:
    movl    n(%rip), %eax #从内存中取n值至寄存器eax
.L3:
    testl   %eax, %eax # 与测试eax
    je  .L3 # eax0时跳转至标号L3处
    movl    $0, %eax
    ret

  真相大白了吧,那该怎么办?对,volatile,参看这里
  所以,在多线程程序中,共享变量除了同步问题外,还要注意编译器的优化和数据的一致性问题。除了多线程程序外,多进程通讯也会有相似的问题,另外,映射到内存的外部端口寄存器变量也需要使用volatile。

Tags: ,.
你好!除了代码,此处没有多少原创之物,皆为本人搜集、整理、总结之记录与心得,欢迎转载分享!转载时请尽量注明出处,将不胜感激。祝你健康、快乐!
Home

Be the first to comment on this entry.

Name(required)
Mail (required),(will not be published)

RFC: Request For Comments. Orz..

Website(recommended)