并发支持库(2)-原子操作

c++中的原子用于实现对象的线程安全的操作,避免数据竞争,每一个原子操作可以看作一个不可分割地整体。

本文章的代码库:https://gitee.com/gamestorm577/CppStd

atomic

atomic是一个类模板,每个atomic模板的实例化都定义了一个原子类型。对于一个原子对象,不同的线程对对象的写入和读取是安全的。atomic不能复制,也不能移动。

c++中为一些基本类型定义了atomic的别名,例如:

using atomic_bool   = atomic<bool>;
using atomic_char   = atomic<char>;
using atomic_schar  = atomic<signed char>;
using atomic_uchar  = atomic<unsigned char>;
using atomic_short  = atomic<short>;
using atomic_ushort = atomic<unsigned short>;
using atomic_int    = atomic<int>;
using atomic_uint   = atomic<unsigned int>;
using atomic_long   = atomic<long>;
using atomic_ulong  = atomic<unsigned long>;
using atomic_llong  = atomic<long long>;
using atomic_ullong = atomic<unsigned long long>;

成员函数

构造函数

默认构造,或者用一个值构造一个atomic对象。代码示例:

std::atomic<int> a_i(20);
std::cout << "a_i = " << a_i << std::endl;

输出结果:

a_i = 20

赋值函数

将值原子地赋值给对象。代码示例:

std::atomic<int> a_i(20);
std::cout << "a_i = " << a_i << std::endl;
a_i = 25;
std::cout << "a_i = " << a_i << std::endl;

输出结果:

a_i = 20
a_i = 25

is_lock_free

检查原子类型的原子操作是否是无锁的。代码示例:

struct A
{int a[100];
};struct B
{int x;int y;
};std::cout << std::boolalpha;
std::cout << "A is_lock_free: " << std::atomic<A>().is_lock_free() << std::endl;
std::cout << "B is_lock_free: " << std::atomic<B>().is_lock_free() << std::endl;

输出结果:

A is_lock_free: false
B is_lock_free: true

store

用指定值原子地替换当前的值。代码示例:

std::atomic<int> a_i(20);
std::cout << "a_i = " << a_i << std::endl;
a_i.store(35);
std::cout << "a_i = " << a_i << std::endl;

输出结果:

a_i = 20
a_i = 35

load

原子地获取原子对象当前的值。代码示例:

std::atomic<int> a_i(25);
std::cout << "a_i = " << a_i.load() << std::endl;

输出结果:

a_i = 25

operator T

原子地返回原子对象当前的值。

exchange

原子地替换对象的值,并返回对象先前持有地值。代码示例:

std::atomic<int> a_i(25);
int num1 = a_i.exchange(30);
int num2 = a_i.load();
std::cout << "num1 = " << num1 << std::endl;
std::cout << "num2 = " << num2 << std::endl;

输出结果:

num1 = 25
num2 = 30

compare_exchange

原子地比较对象地值和Expected,如果是逐位相等的,那么用Desired替换对象的值,否则将对象的值赋给Expected:

bool compare_exchange_strong(TVal& Expected, const TVal Desired,const memory_order Order = memory_order_seq_cst);

代码示例:

std::atomic<int> a_i1(25);
int Expected1 = 33;
a_i1.compare_exchange_strong(Expected1, 17);
std::cout << "ai_1 = " << a_i1 << std::endl;
std::cout << "Expected1 = " << Expected1 << std::endl;std::atomic<int> a_i2(25);
int Expected2 = 25;
a_i2.compare_exchange_strong(Expected1, 17);
std::cout << "ai_2 = " << a_i2 << std::endl;
std::cout << "Expected2 = " << Expected2 << std::endl;

输出结果:

ai_1 = 25
Expected1 = 25
ai_2 = 17
Expected2 = 25

notify_one

唤醒一个原子对象在阻塞中的线程

notify_all

唤醒所有原子对象在阻塞中的线程

wait

比较原子对象的值和Expected,如果相等,则阻塞线程直到被唤醒。否则直接返回:

void wait(const TVal Expected, const memory_order Order = memory_order_seq_cst);

代码示例:

std::atomic<int> a_i(25);
std::thread t = std::thread([&]() {a_i.wait(25);std::cout << "sub thread finish wait" << std::endl;
});std::cout << "main thread" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(3));
a_i.store(17);
a_i.notify_one();t.join();

输出结果:

main thread
sub thread finish wait

常量

is_always_lock_free

指示该类型是否始终免锁

特化成员函数

只有部分类型特化才有的成员函数

fetch_add

原子地加上给定值,并返回对象原来保有的值。

fetch_sub

原子地减去给定值,并返回对象原来保有的值。

fetch_and

原子地进行对象值和给定值的逐位与操作,并返回对象原来保有的值。

fetch_or

原子地进行对象值和给定值的逐位或操作,并返回对象原来保有的值。

fetch_xor

原子地进行对象值和给定值的逐位异或操作,并返回对象原来保有的值。

操作运算符

operator++、operator--令对象的值原子地加一或减一。

operator+=、operator-=、operator&=、operator|=、operator^=对对象值原子地做加、减、逐位与、逐位或、逐位异或操作。

atomic_ref

atomic_ref类模版对它引用的对象应用原子操作。在atomic_ref对象的生命周期中,atomic_ref把其引用的对象看作是一个原子对象。代码示例:

auto Func1 = [](std::vector<int>& arr)
{for (int& num : arr){++num;}
};auto Func2 = [](std::vector<int>& arr)
{for (int& num : arr){auto tmp = std::atomic_ref<int>(num);++tmp;}
};auto test_func = [](std::function<void(std::vector<int>&)> Func)
{std::vector<int> arr(100000, 0);{std::jthread t1(Func, std::ref(arr));std::jthread t2(Func, std::ref(arr));std::jthread t3(Func, std::ref(arr));std::jthread t4(Func, std::ref(arr));}int sum = std::accumulate(arr.begin(), arr.end(), 0);std::cout << "total sum = " << sum << std::endl;
};test_func(Func1);
test_func(Func2);

可能的输出结果:

total sum = 398665
total sum = 400000

原子类型上的操作

c++还提供了原子类型上的函数接口,对应于原子对象的成员函数:

atomic_is_lock_free              is_lock_free    
atomic_store                     store   
atomic_load                      load
atomic_exchange                  exchange
atomic_compare_exchange_weak     compare_exchange_weak
atomic_compare_exchange_stong    compare_exchange_stong
atomic_fetch_add                 fetch_add
atomic_fetch_sub                 fetch_sub
atomic_fetch_and                 fetch_and
atomic_fetch_or                  fetch_or 
atomic_fetch_xor                 fetch_xor
atomic_wait                      wait
atomic_notify_one                notify_one
atomic_notify_all                notify_all

atomic_flag

atomic_flag是一种原子布尔类型,和atomic<bool>不同的是,atomic_flag保证是无锁的。

成员函数

test

原子地返回flag的值。代码示例:

std::atomic_flag af;
std::cout << std::boolalpha;
std::cout << "flag: " << af.test() << std::endl;

输出结果:

flag: false

test_and_set

原子地设置flag为true并返回其先前的值。代码示例:

std::atomic_flag af;
bool flag1 = af.test_and_set();
bool flag2 = af.test();
std::cout << std::boolalpha;
std::cout << "flag1: " << flag1 << std::endl;
std::cout << "flag2: " << flag2 << std::endl;

输出结果:

flag1: false
flag2: true

clear

原子地设置flag为false。代码示例:

std::atomic_flag af;
af.test_and_set();
bool flag1 = af.test();
af.clear();
bool flag2 = af.test();
std::cout << std::boolalpha;
std::cout << "flag1: " << flag1 << std::endl;
std::cout << "flag2: " << flag2 << std::endl;

输出结果:

flag1: true
flag2: false

notify_one

唤醒一个原子对象在阻塞中的线程

notify_all

唤醒所有原子对象在阻塞中的线程

wait

比较原子对象的值和Expected,如果相等,则阻塞线程直到被唤醒。否则直接返回:

void wait(const bool Expected, const memory_order Order = memory_order_seq_cst);

非成员函数

非成员函数对应于atomic_flag的成员函数:

atomic_flag_and_set    flag_and_set
atomic_clear           clear
atomic_test            test
atomic_wait            wait
atomic_notify_one      notify_one
atomic_notify_all      notify_all

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/743968.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电动汽车安全吗?

新能源汽车通常搭载电池系统、电驱动系统以及电控系统&#xff0c;这些部件的安全性能直接关系到整车的安全性。 电动汽车的安全要求通常由国际、国家或地区性的标准和规范来定义和规范。以下是一些常见的电动汽车安全标准&#xff1a; ISO 6469 系列标准&#xff1a;ISO&…

如何在WordPress网站上设置多语言展示

在今天的全球化世界中&#xff0c;拥有多语言网站对于吸引更广泛的受众至关重要。前不就我们遇到Hostease的客户咨询我们的在线客服&#xff0c;他想要对他的wordpress网站支持多语言。我们提供给客户可以尝试以下的插件来支持多语言。 在本教程中&#xff0c;我们将逐步介绍如…

【PCB 小工具】saturnpcb

saturnpcb 官网 打开长这样子&#xff1b; 上面是老版本&#xff1b;看下最新的 推荐还是官方下载 有人在说 这玩意需要在设置板材时候选择&#xff1b;

软件杯 深度学习 opencv python 实现中国交通标志识别

文章目录 0 前言1 yolov5实现中国交通标志检测2.算法原理2.1 算法简介2.2网络架构2.3 关键代码 3 数据集处理3.1 VOC格式介绍3.2 将中国交通标志检测数据集CCTSDB数据转换成VOC数据格式3.3 手动标注数据集 4 模型训练5 实现效果5.1 视频效果 6 最后 0 前言 &#x1f525; 优质…

【Javaweb】【瑞吉外卖】上传下载实现

上传文件 原理&#xff1a;前端让用户选择一个文件&#xff0c;点击丢给后端上传&#xff0c;后端servlet接收到这些请求就进行应答构建连接&#xff0c;完了就开始接收。 但实现这些原理可以不是很懂。servlet封装了一下&#xff0c;spring boot也封装了一下。实现就比较简单…

什么是大顶堆?举个例子

一、什么是大顶堆&#xff1f; 大顶堆&#xff08;Max Heap&#xff09;是一种二叉堆的实现&#xff0c;它满足以下性质&#xff1a; 任意节点的值都大于等于其子节点的值。根节点&#xff08;堆顶&#xff09;的值是整个堆中最大的。 大顶堆通常用于实现优先队列等数据结构…

嘿!终于等到了!应用开发云资源套餐如约而至!

MemFire Cloud平台更新啦&#xff01;&#xff01;此次更新我们推出了万众期待的计费套餐&#xff0c;下面给大家带来详细的介绍~ 计费模式为“基础套餐按量付费”&#xff0c;您可选择购买带有一定配额的基础套餐&#xff0c;超出配额部分可以通过开启“超限按量”功能来转为…

C语言入门学习 --- 4.数组

文章目录 第四章数组1.一维数组的创建与初始化。1.1一维数组的创建1.2一维数组的初始化1.3一维数组的使用1.4一维数组在内存中的存储 2.二维数组的创建与初始化2.1二维数组的创建2.2二维数组的初始化2.3二维数组的使用 2.4二维数组在内存中的存储3.数组越界4.数组作为函数参数4…

AbilityStorage理解与反思

1.简介&#xff1a; AbilityStage是一个Module级别的组件容器&#xff0c;应用的HAP在首次加载时会创建一个AbilityStage实例&#xff0c;可以对该Module进行初始化等操作。 2.那么Module分为三类&#xff1a;Hap,Har,Hsp 官网上的表述容易误解&#xff1a;实际上AbilitySta…

表单修饰符和事件修饰符

表单修饰符和事件修饰符 表单修饰符 v-model.lazy v-model.lazy 失去焦点后再收集数据 <div id"app"><textarea name"" id"" cols"30" rows"10" v-model.lazy"a"></textarea>{{a}}<textar…

【深度学习】深度估计,Depth Anything Unleashing the Power of Large-Scale Unlabeled Data

论文标题&#xff1a;Depth Anything Unleashing the Power of Large-Scale Unlabeled Data 论文地址&#xff1a;https://arxiv.org/pdf/2401.10891.pdf 项目主页&#xff1a;https://depth-anything.github.io/ 演示地址&#xff1a;https://huggingface.co/spaces/LiheYoung…

PyCharm 中 Python 解释器的配置

温馨提示&#xff1a;本文 PyCharm 版本是 2022.3.3 前言 作为 Python 新手&#xff0c;在了解了基本语法之后&#xff0c;肯定得先用 IDE 工具写个 Hello World&#xff0c;来了解 Python 编程语法及 IDE 工具的常规配置和使用&#xff0c;这里我用的 IDE 工具是 PyCharm。 …

C++:构造函数赋初值的几种形式

构造函数用于类对象的初始化&#xff0c;没有返回值也不用写void&#xff0c;函数名与类名相同。构造函数可以有形参也可以无参&#xff0c;构造函数要写在类里边。语法&#xff1a;public: 类名(){ *** }。构造函数在创建对象&#xff08;实例化&#xff09;时会被调用且只有一…

leetcode第49题字母异位词分组

49. 字母异位词分组 给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 输入: strs ["eat", "tea", "tan", "ate", "na…

2024年服务器硬件知识普及篇(需要配置服务器的朋友可以参考)

嘿&#xff0c;大家好&#xff01;今天我们要聊一聊服务器硬件。无论你是想自己搭建一个服务器&#xff0c;还是对服务器硬件感兴趣&#xff0c;这篇文章都会对你有所帮助。我会尽量用简单易懂的语言&#xff0c;带你了解服务器硬件的基础知识。准备好了吗&#xff1f;让我们开…

unicloud update 修改

update 修改 使用腾讯云时更新方法必须搭配doc、where方法使用&#xff0c;db.collection(‘test’).update()会报如下错误&#xff1a;param should have required property ‘query’ collection.doc().update(Object data)未使用set、remove更新操作符的情况下&#xff0c…

odoo中_name_search用法

_name_search是Odoo中一个重要的方法&#xff0c;用于实现模型记录的搜索逻辑。这个方法通常在后端被调用&#xff0c;以便在Odoo的各种视图中&#xff08;如下拉列表选择框&#xff09;搜索和筛选记录。_name_search是模型中的一个API方法&#xff0c;可以被重写以自定义搜索逻…

一维数组_校门外的树

任务描述 某校大门外长度为L的马路上有一排树&#xff0c;每两棵相邻的树之间的间隔都是1米。我们可以把马路看成一个数轴&#xff0c;马路的一端在数轴0的位置&#xff0c;另一端在L的位置&#xff1b;数轴上的每个整数点&#xff0c;即0&#xff0c;1&#xff0c;2&#xff…

如何通过libusb直接向zebra打印机发送zpl,跨平台win/linux

环境&#xff1a;windows & linux & Zebra打印机gt820 windows: 之前安装了Zebra打印机官方驱动&#xff0c;所以先卸载掉驱动。再安装Zadig&#xff0c;用Zadig工具来安装WinUSB驱动。 zadig下载&#xff1a;Zadig - USB driver installation made easy 记住这两个数…

基金评价指标3——滚动收益率测算(近N日收益率,当周/月/年平均收益率)

文章目录 各个指标1. 近N日收益率2. 当周/月/年平均收益率 示例代码 各个指标 1. 近N日收益率 近N日收益率 (当日累计收益 - N日前的累计收益) / N日前的累计收益 2. 当周/月/年平均收益率 这里需要区分不同时间段的起始与终止区间 区间收益率 (区间终值累计收益 - 区间…