`
aigo
  • 浏览: 2648778 次
  • 性别: Icon_minigender_1
  • 来自: 宜昌
社区版块
存档分类
最新评论

榨干性能:C++11中的原子操作(atomic operation)

c++ 
阅读更多

原文:http://www.chenlq.net/books/cpp11-faq/c-pieces-the-drained-performance-c-11-atomic-operation-the-atomic-operation.html

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

在以往的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:SourceCodeMinGW>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:SourceCodeMinGW>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:SourceCodeMinGW>thread.exe
result:100000000
duration:2105ms

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

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

分享到:
评论

相关推荐

    C++ 11 开发中的 Atomic 原子操作.rar_C++11、原子_atomic c++_c++ atomic使用_c++

    C++11引入了原子操作(Atomic Operations)作为标准库的一部分,这为多线程编程提供了重要的支持。原子操作在并发环境下确保了数据的完整性,防止了数据竞争和其他并发问题。下面将详细介绍C++11中`std::atomic`的...

    深入理解C++11:C++11新特性解析与应用源代码

    《深入理解C++11:C++11新特性解析与应用源代码》是一本专为C++开发者设计的书籍,旨在帮助读者掌握C++11标准中的新特性和最佳实践。C++11是C++语言的一个重大更新,引入了许多重要的改进,包括语法上的优化、性能...

    安全栈表实现,C++11实现,使用atomic特性

    C++11引入了原子操作(Atomic Operations)库,提供了对数据访问的原子性,从而在并发编程中保证了数据的安全性。本篇将深入探讨如何使用C++11的原子特性来实现一个安全的栈。 首先,`atomic`类模板是C++11标准库中...

    windows c++ 原子操作例子

    在Windows平台上,C++编程中使用原子操作(Atomic Operations)是为了保证多线程环境下的数据一致性,避免竞态条件和死锁等问题。原子操作是指在多线程环境下,该操作会被完整无中断地执行,不会被其他线程打断。...

    详解C++11原子类型与原子操作

    C++11原子类型与原子操作是C++11标准库中的一项重要特性,它提供了原子类型和原子操作的支持,帮助开发者轻松实现多线程程序中的原子操作。下面是C++11原子类型与原子操作的相关知识点: 1. 认识原子操作 原子操作...

    C++多线程原子操作

    在C++编程中,多线程环境下的原子操作(Atomic Operations)是确保程序并发执行时数据一致性的重要机制。原子操作是指不可分割的操作,一旦开始执行,就不会被其他线程中断,直到该操作完成。在多线程环境中,不使用...

    C++11并发编程关于原子操作atomic的代码示例

    今天小编就为大家分享一篇关于C++11并发编程关于原子操作atomic的代码示例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

    C++ ISO 11标准类型

    11. **原子操作(Atomic Operations)**:`&lt;atomic&gt;`库提供了原子操作,用于在多线程环境中保证数据的完整性,如`std::atomic&lt;int&gt;`。 这些新特性不仅提升了C++的表达力,还优化了性能,使C++更适合现代软件开发的...

    atomic_ops原子操作1

    atomic_ops 是 Linux 内核中的一种原子操作,用于实现原子 counter、Bit 操作和 spinlock 接口。下面将对 atomic_ops 的原子操作进行详细介绍。 atomic_t 类型 atomic_t 是一种原子类型,用于实现原子操作。它...

    C++11新规范(维基百科中文)本地打开可用

    12. **范围for循环(Range-based For Loop)**:C++11的范围for循环简化了遍历容器的操作,如`for(auto& item : container) {...}`,使代码更简洁。 13. **统一的构造函数初始化(Uniform Initialization)**:使用...

    C++ 标准库原子库解析

    C++标准库中的原子库,是C++11标准引入的一组用于并发编程的工具。这些工具主要涉及原子操作和相关的同步机制,它们为多线程程序提供了一种能够确保内存操作的原子性和线程间一致性的手段。在并发环境下,一个“原子...

    Effective Modern C++:改善C++11和C++14的42个具体做法(中文版 + 英文版)

    《Effective Modern C++:改善C++11和C++14的42个具体做法(影印版)(英文版)》中包括以下主题:剖析花括号初始化、noexcept规范、完美转发、智能指针make函数的优缺点;讲解std∷move,std∷forward,rvalue引用和...

    一个c++11实现的无锁队列.zip

    2. **C++11的原子操作**:C++11标准库中的`&lt;atomic&gt;`头文件提供了原子类型和操作,如`std::atomic&lt;T&gt;`,它们确保了在多线程环境下的读写操作不会被中断。常见的原子操作有`fetch_add`、`exchange`、`compare_...

    hashtable C++无锁(std_atomic)&U32非0&不可扩大.rar

    在C++中,std::atomic是用于处理原子类型操作的关键工具,它可以确保在多线程环境中的读写操作不会被中断或交错,从而避免数据不一致。在这个无锁哈希表的实现中,std::atomic可能被用在节点的标记、链接字段或其他...

    c++20标准_c++20标准_

    9. **原子浮点数操作(Atomic Floating-Point Operations)**:`std::atomic`增加了对浮点数的支持,使得在并发环境中安全地处理浮点数成为可能。 10. **改进的字面量操作符(Improved Literal Operators)**:C++...

    多线程程序中的原子操作

    1. **利用编译器或库提供的原子操作支持**:大多数现代编译器和编程语言都提供了原子操作的支持,如C++11标准中的`std::atomic`类型。 2. **手动实现锁机制**:当使用低级语言时,可以手动实现锁机制来保证操作的...

    kotlinx.atomicfu,在kotlin中使用原子操作的惯用方法.zip

    Kotlinx.AtomicFu是Kotlin社区的一个开源项目,它提供了在Kotlin中使用原子操作(Atomic Operations)的简便工具和库。这个项目主要是为了解决多线程环境下的并发问题,尤其是在非Java平台如JavaScript或者Native上...

    C++17 - The Complete Guide.pdf

    * std::atomic:C++17引入了std::atomic类,允许开发者实现原子操作。 错误处理 C++17引入了许多新的错误处理机制,包括: * std::error_code:C++17引入了std::error_code类,允许开发者表示错误代码。 * std::...

Global site tag (gtag.js) - Google Analytics