C++原子操作 atomic的使用及效率

1. 概述
原子操作,它表示在多个线程访问同一个全局资源的时候,能够确保所有其他线程都不在同一时间访问该资源。也就是确保了在同一时刻只有一个线程对这个资源进行访问。这有点类似互斥对象对共享资源的访问的保护,但是原子操作更加接近底层,因而效率更高。

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

2. 实现原理

1. 使用总线锁保证原子性

2. 使用缓存锁保证原子性

详细原理可见我的另一篇博客 https://blog.csdn.net/yzf279533105/article/details/90451557

3. 实验结论(多线程操作全局变量,三个线程,每个线程对整型自增1000万次)

1. 非原子操作,不加锁,效率很高,但无法得到正确的结果

2. 非原子操作,加锁,效率很低,大约和无锁的相差20倍,但结果正确

3. 原子操作,效率很高,大约是有锁实现的5倍,且结果正确

4. 实验结果如下图(已附上编译命令)

1. 非原子,无锁

2. 非原子,有锁

3. 原子

5. 实验代码如下:

1. 非原子操作,且无锁

#include<iostream>
#include<atomic>
#include<thread>
#include<vector>
using namespace std;

int num = 0;

// 线程函数,内部对num自增1000万次
void Add()
{
    for(int i=0;i<10000000;i++) 
    {
        num++;
    }
}

int main()
{
    clock_t startClock = clock();   // 记下开始时间
    // 3个线程,创建即运行
    thread t1(Add);
    thread t2(Add);
    thread t3(Add);
    // 等待3个线程结束
    t1.join();
    t2.join();
    t3.join();
    clock_t endClock = clock();     // 记下结束时间
    cout<<"耗时:"<<endClock-startClock<<",单位:"<<CLOCKS_PER_SEC<<",result:"<<num<<endl;
    return 0;
}

2. 非原子操作,有锁

#include<iostream>
#include<atomic>
#include<thread>
#include<vector>
#include<mutex>
using namespace std;

int num = 0;
mutex mu; 

// 线程函数,内部对num自增1000万次
void Add()
{
    for(int i=0;i<10000000;i++) 
    {
        mu.lock();
        num++;
        mu.unlock();
    }
}

int main()
{
    clock_t startClock = clock();   // 记下开始时间
    // 3个线程,创建即运行
    thread t1(Add);
    thread t2(Add);
    thread t3(Add);
    // 等待3个线程结束
    t1.join();
    t2.join();
    t3.join();
    clock_t endClock = clock();     // 记下结束时间
    cout<<"耗时:"<<endClock-startClock<<",单位:"<<CLOCKS_PER_SEC<<",result:"<<num<<endl;
    return 0;
}

3. 原子操作

#include<iostream>
#include<atomic>
#include<thread>
#include<vector>
#include<atomic>
using namespace std;

atomic<int> num (0);

// 线程函数,内部对num自增1000万次
void Add()
{
    for(int i=0;i<10000000;i++) 
    {
        num++;
    }
}

int main()
{
    clock_t startClock = clock();   // 记下开始时间
    // 3个线程,创建即运行
    thread t1(Add);
    thread t2(Add);
    thread t3(Add);
    // 等待3个线程结束
    t1.join();
    t2.join();
    t3.join();
    clock_t endClock = clock();     // 记下结束时间
    cout<<"耗时:"<<endClock-startClock<<",单位:"<<CLOCKS_PER_SEC<<",result:"<<num<<endl;
    return 0;
}

 

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页