概述
原子计数操作 — _syn_fetch_and_add等12个操作
多线程计数操作,共享状态或者统计相关时间次数,这些都需要在多线程之间共享变量和修改变量,如此就需要在多线
程间对该变量进行互斥操作和访问.我们谭老先生早都说过了! ++i 和 i++都是不是原子性的,本质上为三步:
1. 从缓存取到寄存器
2. 在寄存器中加1
3. 再存入缓存
但是有时候由于时序的元素,多线程操作同一个全局变量,就会出现很多问题,这就是多线程并发编程的难点,尤其随
着计算器硬件技术的快速发展,多CPU多核技术更是彰显出这种困难.
其实最有效的方法就是加互斥量,后来在我们的C++11当中,提供了_syn_fetch_and_add一系列命令进行原子性操作,
随后就在网上查阅相关资料,今天将他们积累下来:
_sync_fetch_and_add系列一共有12个函数,分别:加/减/与/或异或等原子性操作函数,_syn_fetch_and_add,顾明
思义,先fetch,返回自加前的值,举例说明,count = 4,调用_sync_fetch_and_add(&count,1)之后,返回值是4,但
是count变成5. 同样的 __sync_add_and_fetch,先自加,然后返回自加后的值,这样对应的关系,与i++和++i的关系
是一样的. 12个函数如下所示:
type __sync_fetch_and_add (type *ptr, type value, ...)
type __sync_fetch_and_sub (type *ptr, type value, ...)
type __sync_fetch_and_or (type *ptr, type value, ...)
type __sync_fetch_and_and (type *ptr, type value, ...)
type __sync_fetch_and_xor (type *ptr, type value, ...)
type __sync_fetch_and_nand (type *ptr, type value, ...)
type __sync_add_and_fetch (type *ptr, type value, ...)
type __sync_sub_and_fetch (type *ptr, type value, ...)
type __sync_or_and_fetch (type *ptr, type value, ...)
type __sync_and_and_fetch (type *ptr, type value, ...)
type __sync_xor_and_fetch (type *ptr, type value, ...)
type __sync_nand_and_fetch (type *ptr, type value, ...)
上述12个函数即为所有,通过函数名字就可以知道函数的作用,需要注意的是,这个type不能乱用(type 只能是int ,
long ,long long以及对应的unsigned的类型) . 这里还有类似的原子操作:
bool __sync_bool_compare_and_swap(type *ptr, type oldval, type newval, ...)
type __sync_val_compare_and_swap(type *ptr, type oldval, type newval, ...)
这两个函数提供院子的交换和比较,如果 *ptr == oldval,就将newval写入 *ptr,第一个函数在相等并写入的情况下返
回true,第二个函数在返回操作之前的值.
有了这些装逼利器,对于多线程对全局变量进行操作(自加,自减)问题,我们就不用考虑线程锁,可以考虑使用上述
函数代替和使用pthread_mutex保护的作用是一样的,线程安全且性能完爆线程锁. 那么性能好在哪里呢 ?
下面简单介绍一下 __syn_fetch_and_add反汇编出来的指令:
804889d:f0 83 05 50 a0 04 08 lock addl $0x1,0x804a050
可以看到,add前面有一个Lock,这行汇编指令前面是f0开头,f0叫做指令前缀,Richard Blum,lock前缀的意思是对内存区
域的排他性访问.、
其实,lock是锁FSB,前端串行总行,Front Serial Bus,这个FSB是处理器和RAM直接的总线,锁住FSB,就能阻止其他处
理器或core从RAM获取数据,当然这种操作开销相当大,只能操作小的内存才可以这有做. 如果操作一大片内存,锁内存
,那么代价太大了,所以前面介绍__sync_fetch_and_add等函数,type只能是int long longlong以及对应的unsigned类型.
今后写项目切记,加加减减出现竞态现象的时候,一定要记起来使用这个函数! 看网上做实验比mutex性能好.
最后
以上就是背后八宝粥为你收集整理的原子计数操作 — _syn_fetch_and_add等12个操作的全部内容,希望文章能够帮你解决原子计数操作 — _syn_fetch_and_add等12个操作所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复