原子变量和原子操作

一、什么是原子操作

通常某一个变量的操作对应的CPU指令是大于一个的,在多线程环境下,为了确保对共享变量的操作在执行时不会被干扰,从而避免竞态条件和死锁等问题,使用原子变量。

原子变量可以看作是一种特殊的类型,它具有类似于普通变量的操作,但是这些操作都是原子操作,即要么全部完成,要么全部未完成。C++标准库提供了丰富的原子类型,包括整型、指针、布尔值等。通过std::atomic可以定义一个原子变量。

std::atomic<T>
is_lock_free: 是否支持无所操作
store(T desired, std::memory_order order): 写操作,用于将指定的值存储到原子变量中 
load(std::memory_order order): 读操作,用于获取原子变量的当前值
exchange(std::atomic<T> *obj, T desired): 访问和修改原子变量的值,将原子变量的值替换为 desired,并返回原来的值
compare_exchange_weak(T& expected, T val, memory_order success, ,memory_order failure): 比较一个值和期望值是否相等,如果不相等则将该值替换为一新值并返回 false,否则不做任何操作并返回 true.

二、原子性

1. 单处理器单核的情况

需要保证操作指令序列不被打断,实现机制:
屏蔽中断、底层自旋锁

2. 多核或者多处理器

除了不被打断,还需要避免其它核心操作相关的内存空间,实现方法:
lock 指令阻止其它核心对相关内存空间的访问

3. MESI 一致性协议

MESI 协议是一个基于失效的缓存一致性协议,支持 write-back 写回缓存的常用协议。
总线嗅探策略:将读写请求通过总线广播给所有核心,核心根据本地状态进行响应

Cache Line中的 flag 的四种状态:
Modified: 已修改,某个数据块在某核心中已修改但是没有同步到内存中
Exclusive: 独占,某个数据块只在某一个核心中,并且缓存和内存中的数据一致的
Shared: 共享,某个数据块在多个核心中加载,并且缓存和内存中数据一致
Involidated: 已失效,某个数据在核心中已失效,不是最新的数据

事件:

  • PrRd : 核心从缓存中读取数据请求
  • PrWr : 核心从缓存中写入数据请求
  • BusRd : 总线嗅探器收到来自其它核心的读出缓存数据请求
  • BusRdX : 总线嗅探器收到另一个核心写一个其不拥有的缓存块的请求
  • BusUpgr : 总线嗅探器收到另一个核心写一个其拥有的缓存块的请求
  • Flush : 总线嗅探器收到另一个核心把一个缓存块写回到主存的请求
  • FlushOpt :总线嗅探器收到一个缓存块被放置在总线以提供给另一核心的请求,和 Flush 类似但是为缓存到缓存的数据传输

状态机

三、内存序

为什么有内存序问题:

编译器优化重排
CPU指令优化重排

内存序规定了什么

规定了多个线程访问同一个内存地址时的语义:

  1. 某个线程对内存地址的更新何时能被其它线程看到
  2. 某个线程对内存地址访问附近可以做什么样的优化

内存模型

C/C++11标准中提供了6种memory order,来描述内存模型

enum memory_order {memory_order_relaxed,memory_order_consume,memory_order_acquire,memory_order_release,memory_order_acq_rel,memory_order_seq_cst
};
memory_order_relaxed

relaxed表示一种最为宽松的内存操作约定,仅仅保证load()和store()是原子操作, 除此之外,不提供任何跨线程的同步,不干预编译器或CPU的优化

memory_order_release

在写入某原子对象时,当前线程的仍任何前面的读写操作都不允许重排到这个操作的后面,并且当前线程的所有内存写入都在对同一个原子对象进行获取的其它线程可见。通常与 memory_order_acquire 配对使用

memory_order_acquire

在读取某原子对象时,当前线程的任何后面的读写操作都不允许重排到这个操作的前面去,并且其它线程在对同一个原子对象释放之前的所有内存写入都在当前的线程中可见。通常与 memory_order_release 配合使用

memory_order_acq_rel

同时存在读写操作,前后读写操作都不允许重排。当前线程的所有内存写入都在对同一个原子对象进行获取的其它线程可见

memory_order_sec_cst

是所有原子操作的默认内存序,最严格的顺序一致性。会对所有使用此模型的原子操作建立一个全局顺序,保证了多个原子变量的操作,在所有线程里观察到的操作顺序相同,当然它是最慢的同步模型

四、使用原子操作实现无锁队列

使用场景

高性能、低延时场景中如信号处理程序,硬实时系统

MPSC队列具体实现

#include <atomic>
#include <utility>template<typename T>
class MPSCQueue{
private:struct Node{Node() = default;explicit Node(T* data) : Data(data){Next.store(nullptr, std::memory_order_relaxed);}T* Data;std::atomic<Node*> Next;};std::atomic<Node*> _head;std::atomic<Node*> _tail;
public:MPSCQueue() : _head(new Node()), _tail(_head.load(std::memory_order_relaxed)){Node* front = _head.load(std::memory_order_relaxed);front->Next.store(nullptr, std::memory_order_relaxed);}void Enqueue(T* input){Node* node = new Node(input);Node* prevHead = _head.exchange(node, std::memory_order_acq_rel);prevHead->Next.store(node, std::memory_order_release);}bool Dequeue(T*& result){Node* tail = _tail.load(std::memory_order_relaxed);Node* next = tail->Next.load(std::memory_order_acquire);if (!next)return false;result = next->Data;_tail.store(next, std::memory_order_release);delete tail;return true;}~MPSCQueueNonIntrusive(){T* output;while (Dequeue(output))delete output;Node* front = _head.load(std::memory_order_relaxed);delete front;}
};

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

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

相关文章

php基础学习之函数

基本概念 是一种语法结构&#xff0c;将实现某一个功能的代码块封装到一个结构中&#xff0c;从而实现代码的重复利用 php函数的定义语法 &#xff08;与C/Java很类似&#xff0c;区别在于没有数据类型&#xff0c;因为php是弱类型语言&#xff09; function 函数名(参数){ //…

会计财税答案怎么查找?推荐你使用这五个公众号和工具 #知识分享#微信

当今社会&#xff0c;随着信息技术的迅猛发展&#xff0c;大学生们在学习过程中面临着各种各样的困难和挑战。而在这些挑战中&#xff0c;面对繁重的作业和复杂的题目&#xff0c;大学生搜题软件应运而生 1.题小聪 这个是公众号 电大国开试题库为主&#xff0c;搜题效率挺高…

Linux 查看 系统基本信息 uname

基本用法&#xff1a; 在终端中输入"uname"即可显示系统的内核名称。 可以结合不同的参数使用&#xff0c;获取更详细的系统信息。 常见参数&#xff1a; “-s”&#xff1a;显示操作系统名称。 “-n”&#xff1a;显示网络节点主机名。 “-r”&#xff1a;显示内核版…

Linux之动静态库

今天我们来讲动静态库&#xff01; 首先我们来粗粒度的划分一下动态库和静态库。 动态库就是只有一份库文件&#xff0c;所有想用该库的文件与改库文件建立链接&#xff0c;然后使用。这样可以提高代码复用率&#xff0c;避免重复拷贝产生没必要的内存消耗。 静态库&#xf…

UART通信中的奇偶校验

UART通信中的奇偶校验&#xff1a;提升数据传输可靠性的简单方法 在微控制器&#xff08;MCU&#xff09;和各种电子设备之间的数据通信领域&#xff0c;UART&#xff08;Universal Asynchronous Receiver/Transmitter&#xff0c;通用异步收发传输器&#xff09;协议是一种广泛…

openGauss学习笔记-220 openGauss性能调优-确定性能调优范围-查询最耗性能的SQL

文章目录 openGauss学习笔记-220 openGauss性能调优-确定性能调优范围-查询最耗性能的SQL220.1 操作步骤 openGauss学习笔记-220 openGauss性能调优-确定性能调优范围-查询最耗性能的SQL 系统中有些SQL语句运行了很长时间还没有结束&#xff0c;这些语句会消耗很多的系统性能&…

Django CORS 跨域问题解决

座右铭&#xff1a;怎么简单怎么来&#xff0c;以实现功能为主。 欢迎大家关注公众号与我交流 环境安装 pip install django-cors-headers settings.py 修改配置 INSTALLED_APPS ["","corsheaders", # 加上这个"", ]MIDDLEWARE ["cors…

软件项目版本与文档管理的最佳实践

在软件项目开发过程中&#xff0c;版本管理和项目文档管理是至关重要的一环。它们直接影响到项目的顺利进行和最终成果的质量。然而如何有效地管理和维护这些信息&#xff0c;同时保持独立和客观的态度&#xff0c;是每个开发者都需要掌握的技能。本文将探讨如何在软件开发过程…

HCIA-HarmonyOS设备开发认证V2.0-轻量系统内核基础-消息队列queue

目录 一、消息队列基本概念二、消息队列运行机制三、消息队列开发流程四、消息队列使用说明五、消息队列接口六、代码分析&#xff08;待续...&#xff09;坚持就有收获 一、消息队列基本概念 队列又称消息队列&#xff0c;是一种常用于任务间通信的数据结构。队列接收来自任务…

BossPlayerCTF

靶场环境问题 靶场下载之后&#xff0c;可能会出现扫描不到IP的情况&#xff0c;需要进行调整&#xff0c;参考&#xff1a; Vulnhub靶机检测不到IP地址_vulnhub靶机nmap扫不到-CSDN博客 该靶机没有vim&#xff0c;需要使用vi命令去修改&#xff1b;改成当前网卡即可&#x…

第21讲关于我们页面实现

关于我们页面实现 关于锋哥页面author.vue 我们这里用一个vip宣传页面&#xff0c;套一个web-view <template><web-view src"http://www.java1234.com/vip.html"></web-view> </template><script> </script><style> <…

【Java多线程案例】定时器

1. 定时器简介 定时器&#xff1a;想必大家一定对定时器这个概念不陌生&#xff01;因为它经常出现在我们的日常生活和编程学习中&#xff0c;定时器就好比是一个"闹钟"&#xff0c;会在指定时间处理某件事&#xff08;例如响铃&#xff09;&#xff0c;而在编程世界…

删除 Windows 设备和驱动器中的 WPS网盘、百度网盘等快捷图标

在安装诸如WPS软件、百度云盘、爱奇艺等客户端后&#xff0c;Windows 的“我的电脑”&#xff08;或“此电脑”&#xff09;中的“设备和驱动器”部分会出现对应的软件图标。这种情况被许多技术人员视为不必要的干扰&#xff0c;因此许多用户想要知道如何隐藏或删除这些图标。 …

【初中生讲机器学习】9. 我是怎么用朴素贝叶斯实现垃圾邮件分类的?真的超全!

创建时间&#xff1a;2024-02-14 最后编辑时间&#xff1a;2024-02-15 作者&#xff1a;Geeker_LStar 你好呀~这里是 Geeker_LStar 的人工智能学习专栏&#xff0c;很高兴遇见你~ 我是 Geeker_LStar&#xff0c;一名初三学生&#xff0c;热爱计算机和数学&#xff0c;我们一起加…

leetcode刷题之或操作使用场景

文章目录 概要题目问题分析小结 概要 今天晚上上床前刷了一个leetcode的题目&#xff0c;是leetcode的2103题&#xff0c;因为是个简单题&#xff0c;我只是想复习一下hash表的用法。结果反而让我看到了或操作的使用场景。 题目 总计有 n 个环&#xff0c;环的颜色可以是红、…

Zabbix图形中文乱码问题(显示口口)解决办法

一 切换到zabbix安装目录assets/fonts下&#xff0c;下载字体 这里使用是nginxphp作为zabbix-web展示&#xff0c;使用find 命令查找 进入目录下&#xff0c;将原有字体备份&#xff0c;下载msyh字体 wget https://www.xxshell.com/download/sh/zabbix/ttf/msyh.ttf 二 修改配…

[GYCTF2020]Blacklist

感觉是[强网杯 2019]随便注 的加强版&#xff0c;之前做的是最后可以通过prepare和execute实现对select的绕过&#xff0c;但是这题把这两个关键字也过滤了。 前面堆叠注入没啥问题&#xff0c;卡在了最后读取flag 查看其他师傅的wp&#xff0c;发现这个handler的可以当作丐版s…

CPU-GPU异构并行化APSP算法

一、Floyd-Warshall算法 介绍 Floyd-Warshall算法&#xff08;英语&#xff1a;Floyd-Warshall algorithm&#xff09;&#xff0c;中文亦称弗洛伊德算法或佛洛依德算法&#xff0c;是解决任意两点间的最短路径的一种算法&#xff0c;可以正确处理有向图或负权&#xff08;但…

奔跑吧小恐龙(Java)

前言 Google浏览器内含了一个小彩蛋当没有网络连接时&#xff0c;浏览器会弹出一个小恐龙&#xff0c;当我们点击它时游戏就会开始进行&#xff0c;大家也可以玩一下试试&#xff0c;网址&#xff1a;恐龙快跑 - 霸王龙游戏. (ur1.fun) 今天我们也可以用Java来简单的实现一下这…

FileZilla Server 1.8.1内网搭建

配置环境服务器服务器下载服务器配置服务器配置 Server - ConfigureServer Listeners - Port 协议设置 Protocols settingsFTP and FTP over TLS(FTPS) Rights management(权利管理)Users(用户) 客户端建立连接 配置环境 服务器处于局域网内: 客户端 < -访问- > 公网 &l…