当前位置: 首页 > news >正文

2022-09-04 C++并发编程(十八)

C++并发编程(十八)

  • 前言
  • 一、操作标准整数原子类
  • 总结


前言

对于标准的整数(int, unsigned, long等),C++ 特化了标准整数原子类,相应会有一些算数函数,当然,有一些计算不包括在内,比如乘除。


一、操作标准整数原子类

与前述原子布尔类和原子指针类相同,标准的原子整数类也是用普通整数类初始化,

可判断是否为无锁结构,有读取和写入,原子交换,原子比较交换等操作,并且可以设置原子操作的内存次序。

    //初始化整数原子类对象
    std::atomic<int> atomicInt(0);

    std::atomic<unsigned> atomicUInt(0);

    std::atomic<long> atomicLong(0);

    //判断是否是无锁结构
    std::cout << atomicInt.is_lock_free() << std::endl;

    //原子读取,可配合读操作内存次序
    int testInt = atomicInt.load();

    //原子写入,可配合写操作内存次序
    atomicInt.store(1);

    //原子交换,返回原值,更新值,可配合读改写操作内存次序
    testInt = atomicInt.exchange(2);

    //原子比较交换,与期望值(testInt)比较,相同则更新值,否则将值赋值给期望值(testInt)
    // weak 版本可能出现虚假失败
    //可配合两个内存次序,第一个是读改写(成功更新值),第二个是读(更新值失败)
    while (!atomicInt.compare_exchange_weak(testInt, 3))
    {
    }

    //原子比较交换,与weak版的区别是不会出现虚假失败
    atomicInt.compare_exchange_strong(testInt, 4);

对于标准原子整数类对象,可以进行原子加,减,逻辑与,逻辑或,逻辑异或的函数操作,都可添加读改写类内存次序参数。

    //原子加法,返回原值,更新完成加操作的值
    //可配合读改写内存次序
    testInt = atomicInt.fetch_add(1);

    //原子减法,返回原值,更新完成操作的值
    //可配合读改写内存次序
    testInt = atomicInt.fetch_sub(1);

    //原子与操作,返回原值,更新完成操作的值
    //可配合读改写内存次序
    testInt = atomicInt.fetch_and(1);

    //原子或操作,返回原值,更新完成操作的值
    //可配合读改写内存次序
    testInt = atomicInt.fetch_or(1);

    //原子异或操作,返回原值,更新完成操作的值
    //可配合读改写内存次序
    testInt = atomicInt.fetch_xor(1);

标准整数原子类有比较全面的运算符操作,如自增自减,复合加减,复合逻辑与,或,异或,但符号操作如同其他原子类一样,不可设置内存次序。

    //后置自加操作,返回原值,自加
    testInt = atomicInt++;

    //后置自减操作,返回原值,自减
    testInt = atomicInt--;

    //前置自加,自加并返回更新后的值
    testInt = ++atomicInt;

    //前置自减,自减并返回更新后的值
    testInt = --atomicInt;

    //原子合赋值加
    atomicInt += 1;

    //原子复合赋值减
    atomicInt -= 1;

    //原子复合赋值与
    atomicInt &= 1;

    //原子复合赋值或
    atomicInt |= 1;

    //原子复合赋值异或
    atomicInt ^= 1;

以下是全部代码,可进行debug断点调试,熟悉其性质。

#include <atomic>
#include <iostream>

auto main() -> int
{
    //初始化整数原子类对象
    std::atomic<int> atomicInt(0);

    std::atomic<unsigned> atomicUInt(0);

    std::atomic<long> atomicLong(0);

    //判断是否是无锁结构
    std::cout << atomicInt.is_lock_free() << std::endl;

    //原子读取,可配合读操作内存次序
    int testInt = atomicInt.load();

    //原子写入,可配合写操作内存次序
    atomicInt.store(1);

    //原子交换,返回原值,更新值,可配合读改写操作内存次序
    testInt = atomicInt.exchange(2);

    //原子比较交换,与期望值(testInt)比较,相同则更新值,否则将值赋值给期望值(testInt)
    // weak 版本可能出现虚假失败
    //可配合两个内存次序,第一个是读改写(成功更新值),第二个是读(更新值失败)
    while (!atomicInt.compare_exchange_weak(testInt, 3))
    {
    }

    //原子比较交换,与weak版的区别是不会出现虚假失败
    atomicInt.compare_exchange_strong(testInt, 4);

    //原子加法,返回原值,更新完成加操作的值
    //可配合读改写内存次序
    testInt = atomicInt.fetch_add(1);

    //原子减法,返回原值,更新完成操作的值
    //可配合读改写内存次序
    testInt = atomicInt.fetch_sub(1);

    //原子与操作,返回原值,更新完成操作的值
    //可配合读改写内存次序
    testInt = atomicInt.fetch_and(1);

    //原子或操作,返回原值,更新完成操作的值
    //可配合读改写内存次序
    testInt = atomicInt.fetch_or(1);

    //原子异或操作,返回原值,更新完成操作的值
    //可配合读改写内存次序
    testInt = atomicInt.fetch_xor(1);

    //后置自加操作,返回原值,自加
    testInt = atomicInt++;

    //后置自减操作,返回原值,自减
    testInt = atomicInt--;

    //前置自加,自加并返回更新后的值
    testInt = ++atomicInt;

    //前置自减,自减并返回更新后的值
    testInt = --atomicInt;

    //原子符合赋值加
    atomicInt += 1;

    //原子符合赋值减
    atomicInt -= 1;

    //原子符合赋值与
    atomicInt &= 1;

    //原子符合赋值或
    atomicInt |= 1;

    //原子符合赋值异或
    atomicInt ^= 1;

    return 0;
}

总结

标准整数的原子操作大多可以如同普通整数操作一样方便,只是少了乘除等运算,其他更复杂的操作,直接上锁吧,原子操作一般做不来。

如果是循序学习,标准整数的原子操作只是扩展了部分整数运算,及逻辑运算,新内容并不多,可根据示例仔细了解。

相关文章:

  • 插入一百万数据的最优解分析和耗时
  • DockerFile的基本知识及利用DockerFile构建镜像
  • Spring(二)
  • 计算机毕业设计ssm+vue基本微信小程序的执法助手平台
  • Java项目--网页版音乐播放器(JQuery前端逻辑)
  • windows service 服务器安装 MySQL
  • springboot+mybatis+mysql+Quartz实现任务调度(定时任务,实现可配置)
  • python简介常考面试题目:python是什么,有什么好处,python2和python3的主要区别
  • SpringCloud Stream消息驱动
  • JVisualVM 中线程状态(运行/休眠/等待/驻留/监视)解析
  • 常识——绳结打折法
  • AVL树的特性和模拟实现
  • java剧院售票系统计算机毕业设计MyBatis+系统+LW文档+源码+调试部署
  • SpringBoot-36-分布式理论概述
  • 第一章 Linux及Linux Shell简介
  • python3.6+scrapy+mysql 爬虫实战
  • EventListener原理
  • express.js的介绍及使用
  • gf框架之分页模块(五) - 自定义分页
  • Just for fun——迅速写完快速排序
  • TypeScript迭代器
  • uni-app项目数字滚动
  • vue2.0项目引入element-ui
  • Vue组件定义
  • 分类模型——Logistics Regression
  • 简单易用的leetcode开发测试工具(npm)
  • 力扣(LeetCode)357
  • 聊聊sentinel的DegradeSlot
  • 入口文件开始,分析Vue源码实现
  • 深度解析利用ES6进行Promise封装总结
  • 使用parted解决大于2T的磁盘分区
  • 数据库写操作弃用“SELECT ... FOR UPDATE”解决方案
  • 算法-插入排序
  • 译自由幺半群
  • Play Store发现SimBad恶意软件,1.5亿Android用户成受害者 ...
  • Unity3D - 异步加载游戏场景与异步加载游戏资源进度条 ...
  • zabbix3.2监控linux磁盘IO
  • 回归生活:清理微信公众号
  • # .NET Framework中使用命名管道进行进程间通信
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • (+4)2.2UML建模图
  • (二)换源+apt-get基础配置+搜狗拼音
  • (个人笔记质量不佳)SQL 左连接、右连接、内连接的区别
  • (排序详解之 堆排序)
  • (深入.Net平台的软件系统分层开发).第一章.上机练习.20170424
  • (转)C#调用WebService 基础
  • (转)Oracle 9i 数据库设计指引全集(1)
  • (转)利用ant在Mac 下自动化打包签名Android程序
  • .net 验证控件和javaScript的冲突问题
  • .NET/C# 的字符串暂存池
  • .net6使用Sejil可视化日志
  • .NetCore实践篇:分布式监控Zipkin持久化之殇
  • .net和jar包windows服务部署
  • @data注解_一枚 架构师 也不会用的Lombok注解,相见恨晚
  • @WebService和@WebMethod注解的用法