zoukankan      html  css  js  c++  java
  • 原子操作(待更新)

    转载:https://blog.csdn.net/just_kong/article/details/99289539

    1、原子操作
    原子操作(atomic operation)指的是由多步操作组成的一个操作。如果该操作不能原子地执行,则要么执行完所有步骤,要么一步也不执行,不可能只执行所有步骤的一个子集。
    现代操作系统中,一般都提供了原子操作来实现一些同步操作,所谓原子操作,也就是一个独立而不可分割的操作。在单核环境中,一般的意义下原子操作中线程不会被切换,线程切换要么在原子操作之前,要么在原子操作完成之后。更广泛的意义下原子操作是指一系列必须整体完成的操作步骤,如果任何一步操作没有完成,那么所有完成的步骤都必须回滚,这样就可以保证要么所有操作步骤都未完成,要么所有操作步骤都被完成。
    例如在单核系统里,单个的机器指令可以看成是原子操作(如果有编译器优化、乱序执行等情况除外);在多核系统中,单个的机器指令就不是原子操作,因为多核系统里是多指令流并行运行的,一个核在执行一个指令时,其他核同时执行的指令有可能操作同一块内存区域,从而出现数据竞争现象。多核系统中的原子操作通常使用内存栅障(memory barrier)来实现,即一个CPU核在执行原子操作时,其他CPU核必须停止对内存操作或者不对指定的内存进行操作,这样才能避免数据竞争问题。
    在C++11之前,C++标准中并没有对原子操作进行规定。vs和gcc编译器提供了原子操作的api。
    2、windows原子操作api
    Win32 API中常用的原子操作主要有三类,一种是加1减1操作,一种是比较交换操作,另外一种是赋值(写)操作。
    (1)原子加1减1操作
    LONG InterlockedIncrement( LONG volatile* Addend);
    LONG InterlockedDecrement( LONG volatile* Addend);
    (2)  比较并交换操作
    LONG InterlockedCompareExchange( LONG volatile*Destination, LONG Exchange, LONG Comperand );
    这个操作是先将Comperand的值和Destination指向变量的值进行比较,如果相等就将Exchange变量的值赋给Destination指向的变量。返回值为未修改前的Destination位置的初始值。
    (3)原子写操作
    LONG InterlockedExchange( LONG volatile* Target, LONG Value);
    InterlockedExchange的作用为将Value的值赋给Target指向的变量,返回Target指向变量未被赋值前的值。
    3、GCC编译器提供的原子操作API
    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);
    4、C++11提供的原子操作
    C++11中在<atomic>中定义了atomic模板类,atomic的模板参数类型可以为int、long、bool等等,C++中称为trivially copyable type。atomic_int、atomic_long为atomic模板实例化后的宏定义。atomic具体的原子操作函数可以参考http://www.cplusplus.com/reference/atomic/atomic/?kw=atomic。
    5、原子操作的效率
    (1)不加锁也不使用原子变量的程序
    程序代码:
    输出:
     
    (2)加锁的程序
    程序代码:
     
    输出:
     
    3.使用C++11原子变量的程序
    程序代码和输出:
     

     

     (4)结论
    上面的第一个不加锁程序肯定是最不推荐使用的,因为它的执行结果都不正确。第二个程序是使用的常规锁来解决问题,结果正确,但是耗时较久。第三个程序使用的是C++11引入的原子数据类型,使用它程序结果正确,在运行速度上也比加锁的版本快很多。所以,在我们平常写程序的过程中,推荐使用C++11引入的原子变量。
    6、什么时候使用原子操作
    在多线程并发的条件下,所有不是原子性的操作需要保证原子性时,都需要进行原子操作处理。
    例:
    long count = 0;
    void func()
    {
      count++;
    }
    如果有n个线程同时执行这段代码,所有线程执行完后,count的值不一定等于n。因为count++不是一个原子操作,编译成汇编代码,如下所示:
    MOV   eax, [count] 
    INC  eax
    MOV [count], eax
    在cpu执行时 
    第一步,先将 count所在内存的值加载到寄存器;
    第二步,将寄存器的值自增1;
    第三步,将寄存器中的值写回内存。
    所以当第一个线程将count值加载到寄存器,并完成自增1,这时寄存器中的值为2,如果此时cpu调度将此线程中断,并执行完其它线程后,再将此线程调度执行,此时,会将2写入到count。count最后的值就成了2。如果要确保改结果正确,那么cout++就要使用原子操作类型。
    上述示例中,count的操作如果为count = count + 2,那么也需要原子操作,而如果为count=2或者count==2,则不需要原子操作,因为它们本身的操作就是具有原子性的。
    ————————————————
    版权声明:本文为CSDN博主「justkong」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/just_kong/java/article/details/99289539
  • 相关阅读:
    X-CTF(REVERSE入门) python-trade
    X-CTF(REVERSE入门) getit
    X-CTF(REVERSE入门) csaw2013reversing2
    X-CTF(REVERSE入门) no-strings-attached
    X-CTF(REVERSE入门) insanity
    X-CTF(REVERSE入门) logmein
    面向对象编程的七大设计原则
    二叉树的性质
    Visual Studio 2017 WPF应用(.Net Freamwork)断点调试不命中的解决方法
    C语言读写文件
  • 原文地址:https://www.cnblogs.com/zhiminyu/p/12577886.html
Copyright © 2011-2022 走看看