看一个很简单的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 # eax为0时跳转至标号L3处 movl $0, %eax ret |
真相大白了吧,那该怎么办?对,volatile,参看这里。
所以,在多线程程序中,共享变量除了同步问题外,还要注意编译器的优化和数据的一致性问题。除了多线程程序外,多进程通讯也会有相似的问题,另外,映射到内存的外部端口寄存器变量也需要使用volatile。
你好!除了代码,此处没有多少原创之物,皆为本人搜集、整理、总结之记录与心得,欢迎转载分享!转载时请尽量注明出处,将不胜感激。祝你健康、快乐!
Be the first to comment on this entry.