一:概述

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

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

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

  所需头文件<atomic>

二:错误代码

  1. //全局变量
  2. int g_num = ;
  3.  
  4. void fun()
  5. {
  6. for (int i = ; i < ; i++)
  7. {
  8. g_num++;
  9. }
  10. return ;
  11. }
  12.  
  13. int main()
  14. {
  15. //创建线程1
  16. thread t1(fun);
  17. //创建线程2
  18. thread t2(fun);
  19. t1.join();
  20. t2.join();
  21.  
  22. cout << g_num << endl;
  23. getchar();
  24. return ;
  25. }

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

三:加锁代码

  1. //全局变量
  2. int g_num = ;
  3. mutex m_mutex;
  4.  
  5. void fun()
  6. {
  7. for (int i = ; i < ; i++)
  8. {
  9. m_mutex.lock();
  10. g_num++;
  11. m_mutex.unlock();
  12. }
  13. return ;
  14. }
  15.  
  16. int main()
  17. {
  18. //获取当前毫秒时间戳
  19. typedef chrono::time_point<chrono::system_clock, chrono::milliseconds> microClock_type;
  20. microClock_type tp1 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
  21. long long time1 = tp1.time_since_epoch().count();
  22.  
  23. //创建线程
  24. thread t1(fun);
  25. thread t2(fun);
  26. t1.join();
  27. t2.join();
  28.  
  29. cout << "总数:" << g_num << endl;
  30.  
  31. //获取当前毫秒时间戳
  32. microClock_type tp2 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
  33. long long time2 = tp2.time_since_epoch().count();
  34. cout << "耗时:" << time2 - time1 << "ms" << endl;
  35.  
  36. getchar();
  37. return ;
  38. }

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

四:atomic原子操作代码

  1. //全局变量
  2. atomic<int> g_num = ;
  3.  
  4. void fun()
  5. {
  6. for (int i = ; i < ; i++)
  7. {
  8. g_num++;
  9. }
  10. return ;
  11. }
  12.  
  13. int main()
  14. {
  15. //获取当前毫秒时间戳
  16. typedef chrono::time_point<chrono::system_clock, chrono::milliseconds> microClock_type;
  17. microClock_type tp1 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
  18. long long time1 = tp1.time_since_epoch().count();
  19.  
  20. //创建线程
  21. thread t1(fun);
  22. thread t2(fun);
  23. t1.join();
  24. t2.join();
  25.  
  26. cout << "总数:" << g_num << endl;
  27.  
  28. //获取当前毫秒时间戳
  29. microClock_type tp2 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
  30. long long time2 = tp2.time_since_epoch().count();
  31. cout << "耗时:" << time2 - time1 << "ms" << endl;
  32.  
  33. getchar();
  34. return ;
  35. }

执行结果:多次测试输出均为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. Delphi7中的Char和XE中的Char

    我用FillChar()函数时,发现两个版本中的Char不一样. 在delphi7中 procedure TForm2.Button1Click(Sender: TObject); var s: ar ...

  2. Oracle动态执行表不可访问

    在scott 用户下,执行查询语句是出现"Oracle动态执行表不可访问" 经查,是因为用户权限不够所致,修改scott用户权限语句如下: grant select on V_$s ...

  3. linux 虚拟机 安装 php-7.0.2

    1.安装依赖包 yum -y install libxml2 libxml2-devel openssl openssl-devel libjpeg libjpeg-devel libpng libp ...

  4. [转]解读Unity中的CG编写Shader系列1——初识CG

    CG=C for Graphics  用于计算机图形编程的C语言超集 前提知识点: 1.CG代码必须用 CGPROGRAM ... ENDCG括起来 2.顶点着色器与片段着色器的主函数名称可随意,但需 ...

  5. 第五篇 Python内置函数

    内置函数 abs() delattr() hash() memoryview() set() all()    dict()  help() min() setattr() any()  dir()  ...

  6. java集合类学习笔记之ArrayList

    1.简述 ArrayList底层的实现是使用了数组保存所有的数据,所有的操作本质上是对数组的操作,每一个ArrayList实例都有一个默认的容量(数组的大小,默认是10),随着 对ArrayList不 ...

  7. Qt 学习之路 2(47):视图选择

    Qt 学习之路 2(47):视图选择 豆子 2013年3月28日 Qt 学习之路 2 34条评论 选择是视图中常用的一个操作.在列表.树或者表格中,通过鼠标点击可以选中某一项,被选中项会变成高亮或者反 ...

  8. R语言排序函数汇总

    总结: 1.sort是直接对向量排序,返回原数值: 2.order先对数值排序,然后返回排序后各数值的索引: 3.rank返回原数据各项排名,有并列的情况: 4.arrange是dplyr包中的,可对 ...

  9. C++_友元3-其他友元关系

    友元和类的关系还可以更复杂. 举个例子,假设出现了交互式遥控器,交互式遥控器能够让您回答电视节目中的问题,如果回答错误,电视将在控制器上产生嗡嗡声. 这个例子的问题,可以使用新的友元关系来解决.我把它 ...

  10. [CSU1911]Card Game(FWT)

    [vjudge-CSU1911] FWT_or #include<cstring> #include<iostream> #include<algorithm> # ...