C++原子操作实现互斥
来源:互联网 发布:闲鱼申请淘宝介入几天 编辑:程序博客网 时间:2024/05/21 11:28
在以往的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++原子操作实现互斥
- Linux互斥与同步之原子操作
- 互斥 与 全局原子
- c语言实现互斥
- 原子操作实现
- Linux 原子操作实现
- 顺序表原子操作的实现(C语言)
- C/C++-------------__sync_fetch_and_add 原子操作------------------
- linux互斥与同步 之 原子变量和位操作
- [Linux]互斥机制(中断屏蔽、原子操作、自旋锁、信号量)
- linux驱动中的互斥途径一二:中断屏蔽和原子操作
- 韦东山第12.7课-字符驱动之同步互斥阻塞、原子操作、信号量、阻塞
- [C++]gcc中的原子操作
- 汇编原子操作实现(转载)
- 用汇编实现原子操作
- 原子操作的实现原理
- 原子操作的实现原理
- memcache CAS实现原子操作
- Largest Submatrix of All 1’s--POJ3494
- 【链表4】合并两个排序的链表
- PorterDuffXfermode无法合成图片
- caffe-recurrent/rnn
- POJ 1264 SCUD Busters (凸包面积+判断点是否在凸包内)
- C++原子操作实现互斥
- RSACryptoServiceProvider加密解密签名验签和DESCryptoServiceProvider加解密
- C语言打洞访问基本原理
- PL/SQL性能优化技巧
- Android 中如何获取本app的版本号?
- 分块练习 D
- 剑指Offer 35题 第一个只出现一次的字符 Java版
- 水叮当的舞步(迭代搜索+A*搜索)
- 第三十四讲 项目 用循环累加