12C++11多线程编程之原子操作std::atomic

2023-11-01

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

前言:

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

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

  • 1)互斥量:类模板,保护一段共享代码段,可以是一段代码,也可以是一个变量。
  • 2)原子操作std::atomic:类模板,保护一个变量。

1.2 为何需要原子操作std::atomic
上面可以看到,为何已经有互斥量了,还要引入std::atomic呢,这是因为互斥量保护的数据范围比较大,我们期望更小范围的保护。并且当共享数据为一个变量时,原子操作std::atomic效率更高。
我们看简单分析几行代码:

int g = 0;//有一全局变量
//假设线程A不断读该变量
int t = g;
//线程B不断写
g++;

//那么我们知道,g++这一行是由许多行汇编代码组成的,
//当我在写入的过程中,A线程刚好读,那么读出来的值就可能存在不确定,
//所以必须保护该共享数据,可以是互斥量或者优选std::atomic

2 代码测试

2.1 测试当对一个共享变量不加保护时的结果
注意:多个线程对int这种全局变量同时写入时不会发生异常或者崩溃,只会造成数据紊乱。而对于容器(迭代器)这些,由于编译器明确其合法性和抛出对应异常,多个线程同时写入是会造成程序异常和崩溃的。

#include<iostream>
#include<thread>
#include<string>
#include<vector>
#include<list>
#include<mutex>
#include<future>

using namespace std;

int g = 0;
void mythread(){
	for (int i = 0; i < 2000000; i++) {
		g++;
	}
}

int main(){

	thread t1(mythread);
	thread t2(mythread);
	t1.join();
	t2.join();

	cout << "g的值为:" << g << endl;
	return 0;
}

当我运行上面代码多次时,结果几乎都是小于200000两百万的,实际上是一定小于两百万的(不考虑程序异常),这个有的公司面试时会问到原因。

因为A写入的过程中,B也刚好读到A写入之前的值,那么就造成加了两次,结果值只加了1。例如AB同时读到了2,那么它们都加1了,但是结果为3。并且同时写入时,也可能会出现读到一个未确定的值(概率极其小,程序异常可能会出现),造成写入的结果非常大或者非常小。所以这就很有必要引入原子操作std::atomic,进而保护对应的汇编代码为原子操作。

例如下面结果是:1800030。
在这里插入图片描述

2.2 使用原子操作std::atomic
代码非常简单,将上面的代码改成这样即可。这样无论你运行多少次,结果都是两百万。

//int g = 0;
std::atomic<int> g = 0;

2.3 操作bool类型的std::atomic用法

#include<iostream>
#include<thread>
#include<string>
#include<vector>
#include<list>
#include<mutex>
#include<future>

using namespace std;

//int g = 0;
//std::atomic<int> g = 0;
std::atomic<bool> g = false;
void mythread(){
	while (g == false) {
		cout << "mythread运行中,tid= " << this_thread::get_id() << endl;
		this_thread::sleep_for(chrono::seconds(1));
	}
}

int main(){

	thread t1(mythread);
	thread t2(mythread);
	//睡眠5秒让子线程都退出循环
	this_thread::sleep_for(chrono::seconds(5));
	g = true;
	t1.join();
	t2.join();

	cout << "g的值为:" << g << endl;
	return 0;
}

结果:
在这里插入图片描述

3 原子操作std::atomic支持的运算符

2.1 测试支持的运算符
我们将2.2(省略了,即2.1修改int成std::atomic即可)的原子操作代码拿来测试。

  • 1)测试g = g + 1;
    在这里插入图片描述
  • 2)测试g += 1;
  • 多次运行皆为两百万,支持。
    在这里插入图片描述

2.2 总结std::atomic支持的运算符

  • 1)一般atomic原子操作,针对++、–、+=、&=、|=是支持的。其他的可能不支持。

3 简述原子操作std::atomic的用途

  • 1)一般用户统计。例如统计一共发送了多少数据包,接收了多少个数据包。new了多少次,delete了多少次。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

12C++11多线程编程之原子操作std::atomic 的相关文章

随机推荐

  • keil出现错误declaration is incompatible

    错误来源 ECAT inc STM32appl h 38 error 147 declaration is incompatible with unsigned shortnPdInputSize declared at line 396
  • java.io.FileNotFoundException: open failed: EROFS (Read-only file system)

    在聊天中发视屏的时候 需要获取视屏某一帧的图片 以文件形式上传给服务器 然后就出了这个错 在确定文件读取权限都有的情况下 那么很可能就是路径不对一看果然 String filePah System currentTimeMillis png
  • MySQL主从同步原理

    主从复制 是用来建立一个和主数据库完全一样的数据库环境 称为从数据库 主数据库一般是准实时的业务数据库 原理 数据库有个bin log二进制文件 记录了所有sql语句 我们的目标就是把主数据库的bin log文件的sql语句复制过来 让其在
  • ZOJ1610 线段树区间计数

    这题和之前的某道区间建立正好相反 给整懵了 题意 给定一个长为 8000 8000 8000的区间 每次染色一定长度的区间 最后问你每种颜色的区间有多少段 题解 注意必须建 8000 8000 8000的树 然后模拟下递归过程 蒟蒻只会这么
  • L2-034 口罩发放 (25 分)

    好恶心的一道题 就因为我把有症状的人用set存 结果一直卡在后三个样例 把我恶心吐了 最后实在没法把set改成vector顺便标记一下看看是否访问过一次 然后就过了 我tm改了接近两个小时 结果就卡在这 include
  • sed删除中文字符

    LANG C sed r s x81 xFE x40 xFE g test txt 转载于 https blog 51cto com dellinger 2409040
  • 宽带连接已断开

    宽带连接已断开 故障描述 原因分析 解决方案 1 排查线路接触不良 2 排查WI FI开关冲突 3 排查关闭节能以太网功能冲突 3 排除其他网卡冲突 4 排查ipv6协议 和 Ipv4协议冲突 方案一 取消勾选ipv6协议 方案二 重装或者
  • k8s学习-CKS真题-Dockerfile和deployment优化

    目录 题目 环境搭建 解题 Dockerfile deployment yaml 模拟题 参考 题目 Task 1 分析和编辑给定的 Dockerfile cks docker Dockerfile 基于 ubuntu 16 04 镜像 并
  • [转载] 深入理解log机制

    原文 http feihu me blog 2014 insight into log 诊断日志对于定位和修复问题起着至关重要的作用 曾经很傻很天真的认为输出日志就是仅仅调用printf 或者std cerr 而已 简单的不能在简单了 这种
  • “区块链+影视”将会在影视娱乐界刮起怎样的风?

    当一种技术能够渗透到各个产业 并在各个产业都产生巨大的价值的时候 它的潜力和未来价值就会被更多人所追捧 在过去的一年时间里 区块链这一划时代的技术夺目地进入公众视野 被认为是当前最有可能带来颠覆性改变的技术 进入2018年来 区块链行业已更
  • kettle 教程(一):简介及入门

    介绍 kettle 是纯 java 开发 开源的 ETL工具 用于数据库间的数据迁移 可以在 Linux windows unix 中运行 有图形界面 也有命令脚本还可以二次开发 kettle 的官网是 https community hi
  • HCIA笔记整理

    网络基础 什么是网络 网络就是由网络连接设备通过传输介质将网络终端设备连接起来 进行资源共享 信息传递的平台 交换机 交换机是按照通信两端传输信息的需要 用人工或设备自动完成的方法把要传输的信息送到符合要求的相应路由上的技术统称 交换机的作
  • element 表单动态获取性别

    element 动态获取性别 在前端页面里总是会有根据1和2显示相应的内容 我是小白刚接触这些就感觉无能为力 找了一些资料才有了解决方法 话不多说上代码
  • Postgresql时间处理技巧,每半天,每周,每月和每5分钟统计

    一 每半天 如果有张表log bus runinfo里有一个created date是timestamp类型 如何统计12点前的数据 在 PostgreSQL 中 您可以使用 DATE TRUNC 函数和 WHERE 子句来统计特定时间范围
  • opsForList().rightPushAll 是覆盖,还是添加

    opsForList rightPushAll 是添加 这个方法将给定的所有值添加到列表的最右端 它并不会覆盖列表中已有的任何值
  • while(++i)与 while(i++)

    1 while i 是先执行i 1 再进行判断 再执行循环体 2 while i 是先判断 再执行循环体 再 1 循环结束后 while i 执行完后 i 0 while i 执行完后 i 1 测试代码1 include
  • 正大国际琪貨:做股指期货需要多少保证金?

    股指之前是大户才有机会做 因为需要的条件太高了 一般人玩不来 为什么 看看国内的股指条件 股指的保证金比例是12 14 一手股指保证金大约18万元 啥 这是什么概念 怎么这么贵 哈哈 是不是已经把很多人吓跑了 但这东西 波动的一个点值也很大
  • LSTM简单例子(MATLAB code)

    最近在学习RNN和LSTM 1 http magicly me 2017 03 09 iamtrask anyone can code lstm 2 https zybuluo com hanbingtao note 581764 3 ht
  • GLTF中的Draco编译与测试

    1 GLTF Primitive primitive里面有什么属性 Draco压缩是跟GLTF Primitive primitive息息相关的 下面是 GLTF Primitive 中常见的属性 1 GLTF Accessor indic
  • 12C++11多线程编程之原子操作std::atomic

    1 原子操作std atomic相关概念 前言 原子操作 更小的代码片段 并且该片段必定是连续执行的 不可分割 1 1 原子操作std atomic与互斥量的区别 1 互斥量 类模板 保护一段共享代码段 可以是一段代码 也可以是一个变量 2