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, ...)

这两组函数的区别在于第一组返回更新前的值,第二组返回更新后的值。

type可以是1,2,4或8字节长度的int类型,即:

int8_t / uint8_t
int16_t / uint16_t
int32_t / uint32_t
int64_t / uint64_t

后面的可扩展参数(...)用来指出哪些变量需要memory barrier,因为目前gcc实现的是full barrier(类似于linux kernel 中的mb(),表示这个操作之前的所有内存操作不会被重排序到这个操作之后),所以可以略掉这个参数。

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.
第二个函数在返回操作之前的值。

__sync_synchronize (...)

发出一个full barrier.

关于memory barrier,cpu会对我们的指令进行排序,一般说来会提高程序的效率,但有时候可能造成我们不希望得到的结果,举一个例子,比如我们有一个硬件设备,它有4个寄存器,当你发出一个操作指令的时候,一个寄存器存的是你的操作指令(比如READ),两个寄存器存的是参数(比如是地址和size),最后一个寄存器是控制寄存器,在所有的参数都设置好之后向其发出指令,设备开始读取参数,执行命令,程序可能如下:

    write1(dev.register_size,size);
    write1(dev.register_addr,addr);
    write1(dev.register_cmd,READ);
    write1(dev.register_control,GO);

如果最后一条write1被换到了前几条语句之前,那么肯定不是我们所期望的,这时候我们可以在最后一条语句之前加入一个memory barrier,强制cpu执行完前面的写入以后再执行最后一条:

    write1(dev.register_size,size);
    write1(dev.register_addr,addr);
    write1(dev.register_cmd,READ);
    __sync_synchronize();
    write1(dev.register_control,GO);

memory barrier有几种类型:
    acquire barrier : 不允许将barrier之后的内存读取指令移到barrier之前(linux kernel中的wmb())。
    release barrier : 不允许将barrier之前的内存读取指令移到barrier之后 (linux kernel中的rmb())。
    full barrier    : 以上两种barrier的合集(linux kernel中的mb())。

还有两个函数:

type __sync_lock_test_and_set (type *ptr, type value, ...)
   将*ptr设为value并返回*ptr操作之前的值。

void __sync_lock_release (type *ptr, ...)
     将*ptr置0

示例程序:


#include <stdio.h>
#include <pthread.h>
#include <stdlib.h> static int count = 0; void *test_func(void *arg)
{
        int i=0;
        for(i=0;i<20000;++i){
                __sync_fetch_and_add(&count,1);
        }
        return NULL;
} int main(int argc, const char *argv[])
{
        pthread_t id[20];
        int i = 0;         for(i=0;i<20;++i){
                pthread_create(&id[i],NULL,test_func,NULL);
        }         for(i=0;i<20;++i){
                pthread_join(id[i],NULL);
        }         printf("%d\n",count);
        return 0;
}

参考:

1. http://refspecs.freestandards.org/elf/IA64-SysV-psABI.pdf   section 7.4

2. http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html#Atomic-Builtins

转载:GCC 提供的原子操作的更多相关文章

  1. gcc提供的原子操作函数

    gcc从4.1.2提供了__sync_*系列的built-in函数,用于提供加减和逻辑运算的原子操作.其声明如下: type __sync_fetch_and_add (type *ptr, type ...

  2. GCC 提供的原子操作

    gcc从4.1.2提供了__sync_*系列的built-in函数,用于提供加减和逻辑运算的原子操作. 其声明如下: type __sync_fetch_and_add (type *ptr, typ ...

  3. Atomic Builtins - Using the GNU Compiler Collection (GCC) GCC 提供的原子操作

    http://gcc.gnu.org/onlinedocs/gcc-4.4.3/gcc/Atomic-Builtins.html gcc从4.1.2提供了__sync_*系列的built-in函数,用 ...

  4. <转载>gcc/g++编译

    转载于:http://www.cnblogs.com/yc_sunniwell/archive/2010/07/22/1782678.html 1. gcc/g++在执行编译工作的时候,总共需要4步 ...

  5. 转载 锁机制与原子操作 <第四篇>

    一.线程同步中的一些概念 1.1临界区(共享区)的概念 在多线程的环境中,可能需要共同使用一些公共资源,这些资源可能是变量,方法逻辑段等等,这些被多个线程共用的区域统称为临界区(共享区),临界区的资源 ...

  6. (转载)gcc -l参数和-L参数

    -l参数就是用来指定程序要链接的库,-l参数紧接着就是库名,那么库名跟真正的库文件名有什么关系呢?就拿数学库来说,他的库名是m,他的库文件名是libm.so,很容易看出,把库文件名的头lib和尾.so ...

  7. [转载]GCC 编译使用动态链接库和静态链接库--及先后顺序----及环境变量设置总结

    来自http://blog.csdn.net/benpaobagzb/article/details/51364005 GCC 编译使用动态链接库和静态链接库 1 库的分类 根据链接时期的不同,库又有 ...

  8. GCC提供的几个內建函数

    参考 https://gcc.gnu.org/onlinedocs/gcc-4.3.2/gcc/Other-Builtins.html#Other-Builtins https://en.wikipe ...

  9. Android系统中提供的原子操作

    代码的实现位于文件system/core/include/cutils中 http://androidxref.com/4.4.3_r1.1/xref/system/core/include/cuti ...

随机推荐

  1. shell+vim——05

    ln --->link 链接, 链接有两种: 软连接 ln -s 源文件 目标文件   :相当于创建了一个快捷方式,源文件损坏后这个链接也就失效了 ln -s  a.text  a.text.s ...

  2. 011---Djang的cookie和session

    -------------------------------------------------------------cookie与session------------------------- ...

  3. python基础之数据类型与变量patr2

    一.元素分类 有如下值集合 [11,22,33,44,55,66,77,88,99,90...],将所有大于 66 的值保存至字典的第一个key中,将小于 66 的值保存至第二个key的值中. 即: ...

  4. 5 Post实现django表单

    本节大纲 1.article-detail 评论页面的准备工作 (1)model层创建评论模型 class Comment(models.Model): """创建评论模 ...

  5. Spring mvc+hibernate+freemarker(实战)

    Spring mvc+hibernate+freemarker(实战) 博客分类: Spring Spring mvchibernatefreemarkerwebjava  今天我为大家做了一个 sp ...

  6. 《Cracking the Coding Interview》——第7章:数学和概率论——题目2

    2014-03-20 01:59 题目:有n只蚂蚁在正n边形的n个顶点,同时以同速率开始沿着边走.每只蚂蚁走的方向是随机的,那么这些蚂蚁至少有两只发生碰撞的概率是多少. 解法:只有所有蚂蚁都往一个方向 ...

  7. web自动化测试,定位不到元素的原因及解决方案(持续更新中2018年9月29日)

    主要讲自己在实战中遇到的坑: 1.动态id定位不到元素 分析原因:每次打开页面,ID都会变化.用ID去找元素,每次刷新页面ID都会发生变化. 解决方案:推荐使用xpath的相对路径方法或者cssSel ...

  8. Djano之写api使用django_rest_framework【海瑞博客】

    使用django rest framework 可以更快速和友好的编写api,当然网上有很多教程,对于高手来说相对很简单,对于新手来说,根本搞不明白.那是你没有搞明白你自己的职责,做为后端,我们只要提 ...

  9. elk-filebeat收集docker容器日志

    目录 使用docker搭建elk filebeat安装与配置 docker容器设置 参考文章 首发地址 使用docker搭建elk 1.使用docker-compose文件构建elk.文件如下: ve ...

  10. 孤荷凌寒自学python第五十三天使用python写入和修改Firebase数据库中记录

     孤荷凌寒自学python第五十三天使用python写入和修改Firebase数据库中记录 (完整学习过程屏幕记录视频地址在文末) 今天继续研究Firebase数据库,利用google免费提供的这个数 ...