Nginx中的原子操作

来源:互联网 发布:2017网络综艺节目 编辑:程序博客网 时间:2024/05/17 00:06
原子操作在系统编程中属于基础工具。nginx与其他软件很不一样,它几乎把所有操作系统的功能都封装了一遍,估计是出于编程一致性和可移植性的考虑。对于原子操作,nginx提供一组接口。

这里我们只研究有GCC 4.1以上版本的情况,因为nginx对不同的情况有不同的实现,GCC应该还是比较普遍的吧

先看些基本类型
typedef long ngx_atomic_int_t;typedef unsigned long ngx_atomic_uint_t;typedef volatile ngx_atomic_uint_t ngx_atomic_t;#if (NGX_PTR_SIZE == 8) #define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1)#else #define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1)#endif

GCC中的long类型的长度始终是操作系统的位数,所以这一段代码是可以兼容64位系统的。 另外注意原子类型ngx_atomic_t一定要加上volatile标志,如果不加的话,原子变量可能被编译器优化到寄存器去了,就不可能利用原子操作去实现锁的功能了。  

再看nginx提供了哪些原子操作

#define ngx_atomic_cmp_set(lock, old, set) __sync_bool_compare_and_swap(lock, old, set)#define ngx_atomic_fetch_add(value, add) __sync_fetch_and_add(value, add)#define ngx_memory_barrier() __sync_synchronize() #define ngx_cpu_pause() __asm__("pause")

第一个接口是“如果lock指向的值等于old,那么把lock指向的内存单元设为set,并返回1”,其他情况则返回0;
第二个接口是“将value指向的值增加add,返回增加以前的值”;
第三个接口的功能也有点儿诡异,假如你在代码中放上这个函数,那么编译器就不会为了优化而打乱这个函数前后的指令,这也是为什么它取名叫barrier,相当于一个屏障,阻止编译器把后面的指令搬到barrier前面去;
第四个接口是一条汇编指令,暂停程序运行。
其实后面两个接口跟底层原子操作关系不是非常紧密,可能是作者觉得放在这里最合适吧。
前面说过原子操作是基础设施,我们有很多其他的功能要依赖它,比如实现锁

#define ngx_trylock(lock) (*lock==0 && ngx_atomic_cmp_set(lock, 0, 1))#define ngx_unlock(lock) *(lock) = 0
ngx_trylock顾名思义是尝试着去加锁,能加则加,不能则向调用者报告失败,1代表成功,0代表失败。不过我对这个实现有点儿疑问,直接使用ngx_atomic_cmp_set就可以了啊,为什么还要在前面加一个玩意儿,难道是为了性能?还有一点使用者要注意,lock一定要是ngx_atomic_t类型的,这是个宏,是不会做类型检查的。
ngx_unlock毋庸赘言了吧,就是解锁的。
原创粉丝点击