C++11并发编程关于原子操作atomic的代码示例

一:概述

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

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

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

所需头文件<atomic>

二:错误代码

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

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

三:加锁代码

//全局变量
int g_num = 0;
mutex m_mutex;
void fun()
{
  for (int i = 0; i < 10000000; 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 1;
}

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

四:atomic原子操作代码

//全局变量
atomic<int> g_num = 0;
void fun()
{
  for (int i = 0; i < 10000000; 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 1;
}

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

五:小结

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

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。如果你想了解更多相关内容请查看下面相关链接

(0)

相关推荐

  • C++人工模拟栈实现方法

    在C++中,栈作为一种无可替代的重要数据结构,对于程序员来说异常重要.那么,我们该如何用代码人工模拟栈呢? 首先,设置栈的最大深度(因为这里的栈是由数组实现的,在函数引用传递的过程中必须设置大小). 第二步,初始化栈,就是只要把栈顶指针设置为-1(为什么设置为-1在注意事项里说). 第三步,是判断栈满和判断栈空.这很简单,只要对应判断栈顶指针的状态即可. 第四步,压栈.压栈的函数也不难,就是把栈顶指针上移,然后在新的空间里存放数据. 第五步,弹栈与读栈.弹栈与读栈的唯一区别就是弹栈弹出栈顶元素后

  • C++小知识:不要节约代码行数

    本篇案例来自 KDE4 源码. 错误代码: void LDAPProtocol::del( const KUrl &_url, bool ) { .... if ( (id = mOp.del( usrc.dn() ) == -1) ) { LDAPErr(); return; } ret = mOp.waitForResult( id, -1 ); .... } 说明: 一些程序员竭尽全力想把更多的代码压缩到一行.他们尤其热衷于"if"条件语句,把赋值和比较一次性完成. 一个

  • C/C++语言printf命令使用方法

    在C语言以及其它语言中我们经常看到printf命令,那么怎么使用该命令输出想要的结果呢?下面就为大家演示. 1.printf()函数是一个格式化输出函数, 用户可以通过该命令向标准输出设备输出指定的格式信息.使用的方法是: printf("格式化字符串", 变量).在使用前需要注意的是该命令被定义在stdio.h头文件中(C语言),所以需要在程序中加入#include<stdio.h>.printf()函数是一个格式化输出函数, 用户可以通过该命令向标准输出设备输出指定的格

  • C++构造函数和析构函数的使用与讲解

    构造函数(constructor) 1.构造函数是种特殊的类成员函数,遵循如下规则: a.函数名与类名必须相同. b.没有返回值 例如: class Obj { ... public: Obj() { ... } }; 2.构造函数可以带参数,也可以重载 class Obj { ... public: Obj() { ... } Obj(int x, int y) { ... } }; 3.构造函数和普通成员函数不一样,一般不显示调用.在创建一个对象时,构造函数自动调用(编译器来完成). 析构函

  • C++ 编写DLL文件给易语言调用方法

    摸索了两天了,终于解决了所有问题,在此跟大家分享. 需要三个文件,dll_demo.h.dll_demo.cpp.dll_dome.def 直接上代码: 头文件如下: #ifndef _DLL_DEMO_H_ #define _DLL_DEMO_H_ #ifdef DLLDEMO_EXPORTS #define DLL_DEMO extern "C" __declspec(dllexport) #else #define DLL_DEMO extern "C" __

  • C++利用链表模板类实现简易队列

    本文实例为大家分享了C++利用链表模板类实现一个队列的具体代码,供大家参考,具体内容如下 设计思想:MyQueue.h中对模板类进行声明和实现.首先定义结点的结构体,包含数据和指针域两部分.队列类定义中声明和实现了元素入队,出队,打印队首元素和队列等方法. 注意: 1)模板类的声明和定义不能分开(即不能分别放在.h和.cpp文件里). 2)声明新节点时,如果声明的节点是辅助操作的,可以不用new关键字,例如在析构函数中,直接用:Node<T>* temp:定义即可.如果声明一个新节点加入队列,

  • C++ 单例模式的几种实现方式研究

    单例模式 单例模式,可以说设计模式中最常应用的一种模式了,据说也是面试官最喜欢的题目.但是如果没有学过设计模式的人,可能不会想到要去应用单例模式,面对单例模式适用的情况,可能会优先考虑使用全局或者静态变量的方式,这样比较简单,也是没学过设计模式的人所能想到的最简单的方式了. 一般情况下,我们建立的一些类是属于工具性质的,基本不用存储太多的跟自身有关的数据,在这种情况下,每次都去new一个对象,即增加了开销,也使得代码更加臃肿.其实,我们只需要一个实例对象就可以.如果采用全局或者静态变量的方式,会

  • C++实现递归函数的方法

    递归函数通俗来讲就是自己调用自己本身.这样有很大的好处,代码很方便简洁,把复杂的有规律的运算交给计算机去做. 1.首先定义问题.递归函数(recursion)需要设置一个函数,然后再可以循环往复的执行下去. 2.把问题换成公式. 如把阶乘之和定义为f(n)=n*f(n-1).也就是说n*f(n-1)=n*(n-1)*f(n-2)=...=n*(n-1)*(n-2)*...*1 3.用C++公式编写程序 4.再把递归函数累加 5.完整公式如下 6.输入输出检查之后完全正确 总结:以上就是关于C++

  • C++实现连连看消除算法

    C++连连看消除代码的实现,过程比较复杂. #include<iostream> #include<vector> using namespace std; bool CheckRemove(int x1,int y1,int x2,int y2,int rows,int cols,int ***pArray); void Swap(int &a,int &b); typedef struct { int x; int y; }point; int main() {

  • C++实现连连看游戏核心代码

    这两天研究了一下连连看游戏的源代码,感觉它挺简单的,主要就是判断选中的两张图片能否消去.我参考了网上的源代码(抱歉的是,不记得当时下载的网址了,在此对原作者表示深深的歉意!),然后自己把核心代码整理如下,与大家共享.需要说明的是,这只是核心算法的代码,界面设计和操作的代码均已略去. #include <stdlib.h> #include <time.h> //图片类 class picture { public: int type;//图片的编号,共有n种,从0到n-1 bool

随机推荐