目录

1、原子操作std::atomic相关概念

2、不加锁情况

3、加锁情况

 4、原子操作

5、总结

1、原子操作std::atomic相关概念

原子操作:更小的代码片段,并且该片段必定是连续执行的,不可分割。

1.1 原子操作std::atomic与互斥量的区别

1)互斥量:类模板,保护一段共享代码段,可以是一段代码,也可以是一个变量。

2)原子操作std::atomic:类模板,保护一个变量。

1.2 为何需要原子操作std::atomic

为何已经有互斥量了,还要引入std::atomic呢,这是因为互斥量保护的数据范围比较大,我们期望更小范围的保护。并且当共享数据为一个变量时,原子操作std::atomic效率更高。

2、不加锁情况

#include

#include

#include

#include

using namespace std;

// 全局的结果数据

long total = 0;

// 点击函数

void click()

{

for (int i = 0; i < 10000000; ++i)

{

// 对全局数据进行无锁访问

total += 1;

}

}

int main(int argc, char* argv[])

{

// 计时开始

clock_t start = clock();

// 创建3个线程模拟点击统计

thread th1(click);

thread th2(click);

thread th3(click);

th1.join();

th2.join();

th3.join();

// 计时结束

clock_t finish = clock();

// 输出结果

cout << "result:" << total << endl;

cout << "duration:" << finish - start << "ms" << endl;

return 0;

}

执行结果如下:从执行的结果来看,这样的方法虽然非常快,但是结果不正确

3、加锁情况

#include

#include

#include

#include

#include

using namespace std;

// 全局的结果数据

long total = 0;

mutex m;

// 点击函数

void click()

{

for (int i = 0; i < 10000000; ++i)

{

//加锁

m.lock();

// 对全局数据进行无锁访问

total += 1;

//解锁

m.unlock();

}

}

执行结果:互斥对象的使用,保证了同一时刻只有唯一的一个线程对这个共享进行访问,从执行的结果来看,互斥对象保证了结果的正确性,但是也有非常大的性能损失,从刚才的313ms变成了现在的3858,用了原来时间的10多倍的时间。这个损失够大。

 4、原子操作

#include

#include

#include

#include

using namespace std;

// 全局的结果数据

atomic total = 0;

// 点击函数

void click()

{

for (int i = 0; i < 10000000; ++i)

{

// 对全局数据进行无锁访问

total += 1;

}

}

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

5、总结

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

参考文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: