说明
原子操作是CPU提供的特性,不是每个CPU都支持,各个CPU的支持和底层实现并不一样,下面的例子只以Intel 架构来说明
例子
#include <stdio.h>
#include <pthread.h>
/*
type __sync_fetch_and_add (type *ptr, type value, ...)
__sync_fetch_and_add() / __sync_fetch_and_sub() / __sync_fetch_and_or ...
equal to { tmp = *ptr; *ptr += value; return tmp; }
返回旧值base_val
并且base_val += val
*/
int getAndAdd(int *ptr, int val) {
return __sync_fetch_and_add(ptr, val);
}
/*
type __sync_add_and_fetch (type *ptr, type value, ...)
__sync_add_and_fetch / __sync_sub_and_fetch / __sync_or_and_fetch / __sync_and_and_fetch ...
equal to { *ptr op= value; return *ptr; }
返回新值,新值 += value
*/
int addAndGet(int *ptr, int val) {
return __sync_add_and_fetch(ptr, val);
}
/*
type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...)
equal to {
tmp = *ptr;
if (*ptr == oldval)
*ptr = newval;
return tmp; }
先保存*ptr在临时变量中
判断如果*ptr是否和旧值相等,相等就将newval赋值给*ptr,不相等就不处理
返回tmp
*/
int get(int *val) {
return __sync_val_compare_and_swap(val, 0, 0);
}
/*
__sync_synchronize (...)
内存barrier,避免编译器进行指令前后的优化
*/
void memoryBarrier() {
__sync_synchronize();
}
/*
type __sync_lock_test_and_set (type *ptr, type value, ...)
equal to {
tmp = *ptr;
*ptr = value;
return tmp;
}
先保存旧值
设置新值
返回旧值
*/
int getAndSet(int *ptr, int val) {
return __sync_lock_test_and_set(ptr, val);
}
int base_val = 12;
void *test_atomic(void *arg) {
// 先打印值,再加一
while (1) {
int val = getAndAdd(&base_val, 1);
//int val = base_val ++;
memoryBarrier();
if (val >= 1000) {
break;
}
}
return NULL;
}
int main() {
pthread_t p1, p2;
pthread_create(&p1, NULL, test_atomic, NULL);
pthread_create(&p2, NULL, test_atomic, NULL);
pthread_join(p1, NULL);
pthread_join(p2, NULL);
printf("count: %d\n", base_val);
return 0;
}
总结
- 原子操作只适用于1, 2, 4 或者 8字节的整数,指针操作
- 原子操作只会针对那一条语句有效,如果是多条原子操作堆砌起来的语句,还是不能起到原子操作的作用。比如说如下代码:
int val = getAndAdd(&base_val, 1);
// 在这个窗口不能保证原子操作
int tol = addAndGet(&base_val, 12);
...