• Linux下的原子操作


    linux支持的哪些操作是具有原子特性的?知道这些东西是理解和设计无锁化编程算法的基础。

    __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_and_add,自然也就有__sync_add_and_fetch,呵呵这个的意思就很清楚了,先自加,在返回。他们哥俩的关系与i++和++i的关系是一样的。被谭浩强他老人家收过保护费的都会清楚了。
    有了这个宝贝函数,我们就有新的解决办法了。对于多线程对全局变量进行自加,我们就再也不用理线程锁了。下面这行代码,和上面被pthread_mutex保护的那行代码作用是一样的,而且也是线程安全的。
    __sync_fetch_and_add( &global_int, 1 );
    下面是这群函数的全家福,大家看名字就知道是这些函数是干啥的了。
    在用gcc编译的时候要加上选项 -march=i686
    // sam:在我的服务器上,发现不加都可以。

    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);

    // sam:很纳闷为什么后边要写省略号,是不是还有不需要我们关心的参数?用的时候不需要传参数?下面这两个函数正是哥想要的啦,可以轻松实现互斥锁的功能。
    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 (...)


    还有两个函数:
    type __sync_lock_test_and_set (type *ptr, type value, ...)
    将*ptr设为value并返回*ptr操作之前的值。

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

    __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 ",count);
            return 0;
    }

    参考原文章:

    1、http://blog.csdn.net/hzhsan/article/details/25124901

    2、http://www.linuxidc.com/Linux/2011-06/37403.htm

  • 相关阅读:
    css 边框添加四个角效果
    PS 怎么去掉噪点
    Packet Tracer——添加温度计
    zabbix监控mysql数据
    日常检测
    mysql的基本命令操作
    判断字典中是否有这个单词
    批量创建用户
    检测局域网ip存活状态
    spring boot gradle build:bootRepackage failed
  • 原文地址:https://www.cnblogs.com/dirt2/p/5252894.html
Copyright © 2020-2023  润新知