所谓的原子操作,取的就是“原子是最小的、不可分割的最小个体”的意义,它表示在多个线程访问同一个全局资源的时候,能够确保所有其他的线程都不在同一时间内访问相同的资源。也就是他确保了在同一时刻只有唯一的线程对这个资源进行访问。这有点类似互斥对象对共享资源的访问的保护,但是原子操作更加接近底层,因而效率更高。

在以往的C++标准中并没有对原子操作进行规定,我们往往是使用汇编语言,或者是借助第三方的线程库,例如intel的pthread来实现。在新标准C++11,引入了原子操作的概念,并通过这个新的头文件提供了多种原子操作数据类型,例如,atomic_bool,atomic_int等等,如果我们在多个线程中对这些类型的共享资源进行操作,编译器将保证这些操作都是原子性的,也就是说,确保任意时刻只有一个线程对这个资源进行访问,编译器将保证,多个线程访问这个共享资源的正确性。从而避免了锁的使用,提高了效率。

我们还是来看一个实际的例子。假若我们要设计一个广告点击统计程序,在服务器程序中,使用多个线程模拟多个用户对广告的点击:

#include <boost/thread/thread.hpp>
#include <atomic> 
#include <iostream>
#include <time.h>

using namespace std;
// 全局的结果数据 
long total = 0;

// 点击函数
void click()
{
    for(int i=0; i<1000000;++i)
    {
        // 对全局数据进行无锁访问 
        total += 1;     
    }
}
 
 
int main(int argc, char* argv[])
{
    // 计时开始
    clock_t start = clock();
    // 创建100个线程模拟点击统计
    boost::thread_group threads;
    for(int i=0; i<100;++i) 
    {
        threads.create_thread(click);
    }

threads.join_all();
    // 计时结束
    clock_t finish = clock();
    // 输出结果
    cout<<"result:"<<total<<endl;
    cout<<"duration:"<<finish -start<<"ms"<<endl;
    return 0;
}

从执行的结果来看,这样的方法虽然非常快,但是结果不正确
E:\SourceCode\MinGW>thread.exe
result:87228026
duration:528ms

很自然地,我们会想到使用互斥对象来对全局共享资源的访问进行保护,于是有了下面的实现:

long total = 0;
// 对共享资源进行保护的互斥对象
mutex m;

void click()
{
    for(int i=0; i<1000000;++i)
    {
        // 访问之前,锁定互斥对象
        m.lock();
        total += 1;
        // 访问完成后,释放互斥对象 
        m.unlock();
    }
}
互斥对象的使用,保证了同一时刻只有唯一的一个线程对这个共享进行访问,从执行的结果来看,互斥对象保证了结果的正确性,但是也有非常大的性能损失,从刚才的528ms变成了现在的8431,用了原来时间的10多倍的时间。这个损失够大。
E:\SourceCode\MinGW>thread.exe
result:100000000
duration:8431ms

如果是在C++11之前,我们的解决方案也就到此为止了,但是,C++对性能的追求是永无止境的,他总是想尽一切办法榨干CPU的性能。在C++11中,实现了原子操作的数据类型(atomic_bool,atomic_int,atomic_long等等),对于这些原子数据类型的共享资源的访问,无需借助mutex等锁机制,也能够实现对共享资源的正确访问。

// 引入原子数据类型的头文件
#include <atomic>

// 用原子数据类型作为共享资源的数据类型
atomic_long total(0);
//long total = 0;
 
void click()
{
    for(int i=0; i<1000000;++i)
    {
        // 仅仅是数据类型的不同而以,对其的访问形式与普通数据类型的资源并无区别
        total += 1;
    }
}

我们来看看使用原子数据类型之后的效果如何:
E:\SourceCode\MinGW>thread.exe
result:100000000
duration:2105ms

结果正确!耗时只是使用mutex互斥对象的四分之一!也仅仅是不采用任何保护机制的时间的4倍。可以说这是一个非常不错的成绩了。

原子操作的实现跟普通数据类型类似,但是它能够在保证结果正确的前提下,提供比mutex等锁机制更好的性能,如果我们要访问的共享资源可以用原子数据类型表示,那么在多线程程序中使用这种新的等价数据类型,是一个不错的选择。

【转自:http://imcc.blogbus.com/logs/179131763.html】

C++11中的原子操作(atomic operation)(转)的更多相关文章

  1. 什么是Java中的原子操作( atomic operations)

    1.啥是java的原子性 原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行. 一个很经典的例子就是银行账户转账问题: 比如从账户A向账户B转1000元,那么 ...

  2. C++11中的原子操作(atomic operation)

    所谓的原子操作,取的就是“原子是最小的.不可分割的最小个体”的意义,它表示在多个线程访问同一个全局资源的时候,能够确保所有其他的线程都不在同一时间内访问相同的资源.也就是他确保了在同一时刻只有唯一的线 ...

  3. golang中的原子操作atomic包

    1. 概念 原子操作 atomic 包 加锁操作涉及到内核态的上下文切换,比较耗时,代价高, 针对基本数据类型我们还可以使用原子操作来保证并发的安全, 因为原子操作是go语言提供的方法,我们在用户态就 ...

  4. 原子操作atomic解读

    下面从一个问题引入: // ConsoleApplication5.cpp : 定义控制台应用程序的入口点. #include "stdafx.h" #include<ran ...

  5. 原子操作(atomic operation)

    深入分析Volatile的实现原理 引言 在多线程并发编程中synchronized和Volatile都扮演着重要的角色,Volatile是轻量级的synchronized,它在多处理器开发中保证了共 ...

  6. C++11并发编程:原子操作atomic

    一:概述 项目中经常用遇到多线程操作共享数据问题,常用的处理方式是对共享数据进行加锁,如果多线程操作共享变量也同样采用这种方式. 为什么要对共享变量加锁或使用原子操作?如两个线程操作同一变量过程中,一 ...

  7. 探究Java如何实现原子操作(atomic operation)

    1. 让我们首先了解下java 中 Volatile 关键字 Volatile可实现java内存模型当中的可见性, java内存模型的可见性: 可见性,是指线程之间的可见性,一个线程修改的状态对另一个 ...

  8. C++11 并发指南六(atomic 类型详解四 C 风格原子操作介绍)

    前面三篇文章<C++11 并发指南六(atomic 类型详解一 atomic_flag 介绍)>.<C++11 并发指南六( <atomic> 类型详解二 std::at ...

  9. C++11 并发指南六(atomic 类型详解三 std::atomic (续))

    C++11 并发指南六( <atomic> 类型详解二 std::atomic ) 介绍了基本的原子类型 std::atomic 的用法,本节我会给大家介绍C++11 标准库中的 std: ...

随机推荐

  1. Eclipse常用配置及常用快捷键

    Eclipse常用配置 ① 对编辑窗口视图的字体大小和字体类型进行配置; ②对控制台和xml文本字体大小和字体类型进行设置; ③ 设置.修改eclipse所使用的jdk环境; ④ 设置.修改当前对ja ...

  2. 九度oj 题目1456:胜利大逃亡

    题目描述: Ignatius被魔王抓走了,有一天魔王出差去了,这可是Ignatius逃亡的好机会.魔王住在一个城堡里,城堡是一个A*B*C的立方体,可以被表示成A个B*C的矩阵,刚开始Ignatius ...

  3. php-超全局变量

    下表列出了您能够在 $_SERVER 中访问的最重要的元素: 元素/代码 描述 $_SERVER[' PHP_SELF '] 返回当前执行脚本的文件名. $_SERVER[' GATEWAY_INTE ...

  4. 设计模式(Java随笔)—装饰模式

    装饰模式(Decorator Pattern):为已有功能动态地添加更多功能的一种方式Attach additional responsiblities to an object dynamicall ...

  5. mybatis学习(十二)——mybatis逆向工程

    MyBatis Generator (MBG)是一个mabatis的代码生成器,能够根据表自动生成mapper接口,mapper.xml文件,javaBean文件. 1.MBG的下载 打开https: ...

  6. 【bzoj1717】[Usaco2006 Dec]Milk Patterns 产奶的模式 SA+二分

    Description 农夫John发现他的奶牛产奶的质量一直在变动.经过细致的调查,他发现:虽然他不能预见明天产奶的质量,但连续的若干天的质量有很多重叠.我们称之为一个“模式”. John的牛奶按质 ...

  7. [暑假集训--数位dp]LightOJ1140 How Many Zeroes?

    Jimmy writes down the decimal representations of all natural numbers between and including m and n, ...

  8. 基于css3翻牌效果

    <div class="map_block float_l lineItem"> <a href="javascript:;" class=& ...

  9. 快充 IC BQ25896 的 ICO (input current optimizer)

    ICO (input current optimizer) 手機接上 adapter 後, 手機裡的 charger IC bq25896 開始向 adapter 抽取 current 供給 batt ...

  10. AC日记——[网络流24题]骑士共存 cogs 746

    746. [网络流24题] 骑士共存 ★★☆   输入文件:knight.in   输出文件:knight.out   简单对比时间限制:1 s   内存限制:128 MB 骑士共存问题 «问题描述: ...