什么是原子操作?
所谓原子操作,就是"不可中断的一个或一系列操作" 。在确认一个操作是原子的情况下,多线程环境里面,我们可以避免仅仅为保护这个操作在外围加上性能开销昂贵的锁。
那么,GNU C中x++是原子操作吗?请看下面一段代码:
- #include <stdlib.h>
- #include <pthread.h>
- static int x;
- void inc()
- {
- x++;
- }
- void foo(void)
- {
- int i;
- for (i = 0; i < 5; i++)
- {
- inc();
- }
- }
- int main(int argc, char *argv[])
- {
- pthread_t p1, p2;
- pthread_create(&p1, NULL, (void *)foo, NULL);
- pthread_create(&p2, NULL, (void *)foo, NULL);
- pthread_join(p1, NULL);
- pthread_join(p2, NULL);
- printf("%d/n", x);
- }
代码输出的x值是多少呢?
在多线程编程环境中,对全局变量的访问是需要进行同步保护的,当然也可以借用原子操作,这样程序运行结果才是确定的。所以现在的问题是x++是原子操作吗?如果是,则上述代码运行结果x=10。如果不是,则运行结果是不确定的,x值为 [5, 10]范围中的某个值。x++应该是非原子操作,但我又不是很确定,所以只好看汇编代码了。
inc:
pushl %ebp
movl %esp, %ebp
movl x, %eax
addl $1, %eax
movl %eax, x
popl %ebp
ret
从上面的汇编代码片段,显然可以确定x++是非原子的,它由3条汇编指令组成。因此上面的x的值也就是不确定的了,它的最大值可能为10,最小值可能为5。这两种情况分别发生在完全没有同步(即串行)和完全竞争(即每次均同时读取同样的x值)的情况下,两个极端情形,要得到这样的结果,估计要看RP(开个玩笑,呵呵)。
结论,GNU C中x++不是原子操作,所以特别提供了原子值类型atomic_t。