一:概述

  项目中经常用遇到多线程操作共享数据问题,常用的处理方式是对共享数据进行加锁,如果多线程操作共享变量也同样采用这种方式。

  为什么要对共享变量加锁或使用原子操作?如两个线程操作同一变量过程中,一个线程执行过程中可能被内核临时挂起,这就是线程切换,当内核再次切换到该线程时,之前的数据可能已被修改,不能保证原子操作。

  C++11提供了个原子的类和方法atomic,保证了多线程对变量原子性操作,相比加锁机制mutex.locak(),mutex.unlocak(),性能有几倍的提升。

  所需头文件<atomic>

二:错误代码

 //全局变量
int g_num = ; void fun()
{
for (int i = ; i < ; i++)
{
g_num++;
}
return ;
} int main()
{
//创建线程1
thread t1(fun);
//创建线程2
thread t2(fun);
t1.join();
t2.join(); cout << g_num << endl;
getchar();
return ;
}

应该输出结果20000000,实际每次结果都不一样,总是小于该值,正是由于多线程操作同一变量而没有保证原子性导致的。

三:加锁代码

 //全局变量
int g_num = ;
mutex m_mutex; void fun()
{
for (int i = ; i < ; i++)
{
m_mutex.lock();
g_num++;
m_mutex.unlock();
}
return ;
} int main()
{
//获取当前毫秒时间戳
typedef chrono::time_point<chrono::system_clock, chrono::milliseconds> microClock_type;
microClock_type tp1 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
long long time1 = tp1.time_since_epoch().count(); //创建线程
thread t1(fun);
thread t2(fun);
t1.join();
t2.join(); cout << "总数:" << g_num << endl; //获取当前毫秒时间戳
microClock_type tp2 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
long long time2 = tp2.time_since_epoch().count();
cout << "耗时:" << time2 - time1 << "ms" << endl; getchar();
return ;
}

执行结果:多次测试输出均为20000000,耗时在3.8s左右

四:atomic原子操作代码

 //全局变量
atomic<int> g_num = ; void fun()
{
for (int i = ; i < ; i++)
{
g_num++;
}
return ;
} int main()
{
//获取当前毫秒时间戳
typedef chrono::time_point<chrono::system_clock, chrono::milliseconds> microClock_type;
microClock_type tp1 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
long long time1 = tp1.time_since_epoch().count(); //创建线程
thread t1(fun);
thread t2(fun);
t1.join();
t2.join(); cout << "总数:" << g_num << endl; //获取当前毫秒时间戳
microClock_type tp2 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
long long time2 = tp2.time_since_epoch().count();
cout << "耗时:" << time2 - time1 << "ms" << endl; getchar();
return ;
}

执行结果:多次测试输出均为20000000,耗时在1.3s左右

五:总结

  c++11的原子类atomic相比使用加锁机制性能有2~3倍提升,对于共享变量能用原子类型的就不要再用加锁机制了。

扫码关注公众号

专注分享Java,C/C++,STL,Spring框架,mybatis框架,mysql,redis,分布式,高并发,设计模式,爬虫,docker,shell编程等相关技术,在这里一起探讨,一起学习,一起进步,不定期分享视频书籍资源,充分利用碎片化时间,让我们的技术之路更加有乐趣。

C++11并发编程:原子操作atomic的更多相关文章

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

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

  2. C++11 并发编程库

    C++11 并发编程 C++11 新标准中引入了几个头文件来支持多线程编程,他们分别是: <atomic>:该头文主要声明了两个类, std::atomic 和 std::atomic_f ...

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

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

  4. C++11 并发指南六( <atomic> 类型详解二 std::atomic )

    C++11 并发指南六(atomic 类型详解一 atomic_flag 介绍)  一文介绍了 C++11 中最简单的原子类型 std::atomic_flag,但是 std::atomic_flag ...

  5. C++11 并发编程基础(一):并发、并行与C++多线程

    正文 C++11标准在标准库中为多线程提供了组件,这意味着使用C++编写与平台无关的多线程程序成为可能,而C++程序的可移植性也得到了有力的保证.另外,并发编程可提高应用的性能,这对对性能锱铢必较的C ...

  6. C++11 并发指南六(atomic 类型详解一 atomic_flag 介绍)

    C++11 并发指南已经写了 5 章,前五章重点介绍了多线程编程方面的内容,但大部分内容只涉及多线程.互斥量.条件变量和异步编程相关的 API,C++11 程序员完全可以不必知道这些 API 在底层是 ...

  7. C++11并发编程:多线程std::thread

    一:概述 C++11引入了thread类,大大降低了多线程使用的复杂度,原先使用多线程只能用系统的API,无法解决跨平台问题,一套代码平台移植,对应多线程代码也必须要修改.现在在C++11中只需使用语 ...

  8. C++11并发编程个人小结

    thread_local变量在每个线程第一次执行到时初始化(类似static),并在每个线程各自累加,并在线程结束时释放. std::condition_variable:: wait(std::un ...

  9. C++11并发编程:async,future,packaged_task,promise

    一:async std::async:用于创建异步任务,可以代替创建线程,函数原型:async(std::launch::async | std::launch::deferred, f, args. ...

随机推荐

  1. JavaScript补充:BOM(浏览器对象模型)

    一些公共对象.详细参考手册. 一.Window 对象 Window 对象表示浏览器中打开的窗口. 如果文档包含框架(<frame> 或 <iframe> 标签),浏览器会为 H ...

  2. db2中临时表在存储过程中的使用

    DROP PROCEDURE ADMINISTRATOR.SP_TEST (INTEGER, CHARACTER ()); CREATE PROCEDURE administrator.sp_test ...

  3. [转]B+Tree图解

    一,    M阶B+树的定义(M阶是指一个节点最多能拥有的孩子数,M>2): 图1.1 3阶B+树 (1)根结点只有1个,分支数量范围[2,m]. (2)除根以外的非叶子结点,每个结点包含分支数 ...

  4. IIS部署SSL,.crt .key 的证书,怎么部署到IIS

    SSL连接作用不说,百度很多.因为最近想考虑重构一些功能,在登录这块有打算弄成HTTPS的,然后百度了,弄成了,就记录一下,以便以后万一部署的时候忘记掉. 做实验的时候,拿的我个人申请的已经备案的域名 ...

  5. 一个基于 .NET Core 2.0 开发的简单易用的快速开发框架 - LinFx

    LinFx 一个基于 .NET Core 2.0 开发的简单易用的快速开发框架,遵循领域驱动设计(DDD)规范约束,提供实现事件驱动.事件回溯.响应式等特性的基础设施.让开发者享受到正真意义的面向对象 ...

  6. 「BJOI2012」连连看

    题目链接 戳我 \(Solution\) 我们首先进行拆点操作,将每个点都拆成\(x\)和\(y\),将满足条件的两个点连起来就好了(记得要将\(x\)连\(y'\)的同时要将\(y\)联向\(x'\ ...

  7. 数据库处理session类

    <?php /* * 使用数据库处理session * php.ini 中 session.save_handler 设为 "user" */ class Dbsession ...

  8. cinder侧挂载卷流程分析

    cinder侧挂载卷流程分析,存储类型以lvm+iscsi的方式为分析基础cinder侧主要调用了三个接口1)reserve_volume: 把volume的状态改为attaching,阻止其它节点执 ...

  9. 新手必看,Spring Boot CLI 必会必知

    Spring Boot CLI 是什么 Spring Boot CLI 是 Spring Boot Commad Line 的缩写,是 Spring Boot 命令行工具.在 Spring Boot ...

  10. mysql 行转列,对列的分组求和,对行求和

    CREATE TABLE students( id INT PRIMARY KEY, NAME VARCHAR(11)); CREATE TABLE courses( id INT PRIMARY K ...