(一)背景
实现多线程环境下的计数器操作,统计相关事件的次数. 当然我们知道,count++这种操作不是原子的。一个自加操作,本质是分成三步的:
1 从缓存取到寄存器
2 在寄存器加1
3 存入缓存。
由于时序的因素,多个线程操作同一个全局变量,会出现问题。这也是并发编程的难点。在目前多核条件下,这种困境会越来越彰显出来。 最简单的处理办法就是加锁保护,这也是我最初的解决方案。看下面的代码:
pthread_mutex_t count_lock = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&count_lock); global_int++; pthread_mutex_unlock(&count_lock);
后来在网上查找资料,找到了__sync_fetch_and_add系列的命令,发现这个系列命令讲的最好的一篇文章,英文好的同学可以直接去看原文。Multithreaded simple data type access and atomic variables
(二)系列函数
__sync_fetch_and_add系列一共有十二个函数,有加/减/与/或/异或/等函数的原子性操作函数,__sync_fetch_and_add,顾名思义,先fetch,然后自加,返回的是自加以前的值。以count = 4为例,调用__sync_fetch_and_add(&count,1)之后,返回值是4,然后,count变成了5.
简单验证代码如下sync_fetch_add.c:
#include <stdio.h> #include <stdlib.h> int main(int argc, char **argv){ int count = 4; printf("111 count:%d\n",count); int retval = __sync_fetch_and_add(&count,10); printf("222 retval:%d\n",retval); printf("222 count:%d\n",count); return 0; }
linux 系统中命令行执行:gdb -g -o sync_fetch_add sync_fetch_add.c
得到可执行文件,执行后得到如下结果:
./sync_fetch_add
111 count:4
222 retval:4
222 count:14
有__sync_fetch_and_add,自然也就有__sync_add_and_fetch,呵呵这个的意思就很清楚了,先自加,在返回。他们的关系与i++和++i的关系是一样的。有了这个函数,对于多线程对全局变量进行自加,我们就再也不用理线程锁了。下面这行代码,和上面被pthread_mutex保护的那行代码作用是一样的,而且也是线程安全的。
在用gcc编译的时候要加上选项 -march=i686,我在执行上面代码时,gcc没加该参数,使用到的版本gcc version 4.4.7 20120313 , 上面代码能正常运行通过。
下面是这群函数的全部,无非是先fetch再运算,或者先运算再fetch。
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);
GCC 提供的原子操作 gcc从4.1.2提供了__sync_*系列的built-in函数,用于提供加减和逻辑运算的原子操作。
其声明如下:
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, ...)
这两组函数的区别在于第一组返回更新前的值,第二组返回更新后的值。
标签:__,sync,value,fetch,add,type,ptr From: https://www.cnblogs.com/imreW/p/17290674.html