原子操作(cpp atomic)

目录

一.原子操作

1.原子操作的概念

2.原子变量

二.原子性

1.中间状态描述

2.单处理器单核

3.多处理器或多核的情况下

4.cache(高速缓冲器的作用)

5.在cpu cache基础上,cpu如何读写数据???

6.为什么会有缓存一致性问题

7.解决策略

三.内存序

1.为什么有内存序问题???

2.内存序规定了什么

3.六种不同的内存序

4.代码案例

四.总结


一.原子操作

多线程下确保堆共享变量的操作在执行时不会被干扰,从而避免竞态条件

1.原子操作的概念

①.原子操作定义:

对基本类型或指针进行的不可中断的操作。

②.原子性:

确保操作在多线程环境下不被中断,保证线程安全。

③.内存序:

理解内存序的概念,确保操作的同步性和顺序性。

2.原子变量

①autoinc.cc

②原子变量的操作

③原子性

④原子操作是实现和平台相关

二.原子性

1.中间状态描述

要么都做要么都还没做,不会然其他核心看到执行的一个中间状态

2.单处理器单核

①单核单线程我们只需要保证操作的指令不会被中断即可(调用机制)

②在硬件底层有自旋锁

③屏蔽中断:通过关闭处理器的中断功能,让处理器在执行关键代码段的时候,不接收外部的请求从而保证了关键代码段执行的过程中不会被打断

3.多处理器或多核的情况下

除了不被打断还需要避免其他核心操作相关的内存空间

①以往0x86,lock指令锁总线,避免所有内存的访问

②现在lock指令只需要阻止其他核心堆相关内存空间的访问即可

4.cache(高速缓冲器的作用)

为了解决cpu运算速度与内存访问速度不匹配的问题

5.在cpu cache基础上,cpu如何读写数据???

我们可以通过写回策略来决定

①是否命中缓存?

命中直接写并标记为脏 ,没命中则直接往下

②定位缓存块,该数据是否为脏数据?

是脏数据则刷主存,不是脏数据,从内存读取,写入缓存,并标记为脏

①是否命中缓存?

命中直接返回,没命中直接往下

②定位缓存块,该数据是否为脏数据?

是脏数据则刷主存,不是脏数据,从内存读取,写入缓存,并标记为非脏

6.为什么会有缓存一致性问题

①cpu是多核的

②基于写回策略将会出现缓存不一致的问题



7.解决策略

①基于总线嗅探机制实现了事务串行化,通过状态机降低总线带宽的压力

②事务的串行化:“锁”         和         “lock指令”

③MESI一致性协议

三.内存序

1.为什么有内存序问题???

①编译器优化重排

②CPU指令优化重排

2.内存序规定了什么

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

②某个线程对内存地址的更新何时能被其他线程看见

③某个线程对内存地址访问附件可以做什么样的优化

3.六种不同的内存序

std::memory_order_relaxed不保证顺序性,性能优先。

std::memory_order_consume读取数据的顺序不被重排(但现代编译器会优化成 acquire)。

std::memory_order_acquire保证之前的操作不被重排到后面。

std::memory_order_release保证之后的操作不被重排到前面。

std::memory_order_acq_rel结合了 acquirerelease 的特性。

std::memory_order_seq_cst保证全局顺序一致性。

补充::

4.代码案例

std::atomic<bool> x,y;
std::atomic<int> z;void write_x_then_y()
{x.store(true,std::memory_order_relaxed);  // 1y.store(true,std::memory_order_relaxed);  // 2
}void read_y_then_x()
{while(!y.load(std::memory_order_relaxed));  // 3if(x.load(std::memory_order_relaxed))  // 4++z;
}

这种情况下没有指定内存序的位置会导致y先变成true 然后 x依旧是false while结束死循环 if语句判断失败 从而z不会发生++的操作

由于使用了 std::memory_order_relaxedxy 的写操作可能会在内存中被重排,因此 read_y_then_x 线程检查到 xfalse 的情况是可能的。最终,这会导致 z 不一定等于 1,甚至可能为 0,取决于内存重排的情况。

#include <atomic>
#include <thread>
#include <assert.h>
#include <iostream>std::atomic<bool> x,y;
std::atomic<int> z;void write_x_then_y()
{x.store(true,std::memory_order_relaxed);  // 1y.store(true,std::memory_order_release);  // 2
}void read_y_then_x()
{while(!y.load(std::memory_order_acquire));  // 3if(x.load(std::memory_order_relaxed))  // 4++z;
}

这种情况下z的结果一定为1 

因为y读出来是true的时候 x一定也是true

使用了 memory_order_release memory_order_acquire确保了在 y 设置为 true 之后,x 的修改在 read_y_then_x 线程中变得可见。

z 最终会等于 1,因为通过这些内存序约束,线程间的同步得到了保证。

#include <assert.h>
#include <atomic>
#include <thread>
#include <iostream>std::atomic<bool> x, y;
std::atomic<int> z;void write_x() {x.store(true, std::memory_order_seq_cst); // 1
}void write_y() {y.store(true, std::memory_order_seq_cst); // 2
}
void read_x_then_y() {while (!x.load(std::memory_order_seq_cst));if (y.load(std::memory_order_seq_cst)) // 3++z;
}
void read_y_then_x() {while (!y.load(std::memory_order_seq_cst));if (x.load(std::memory_order_seq_cst)) // 4++z;
}
int main() {for (int i = 0; i < 20; i++) {x = false;y = false;z = 0;std::thread a(write_x);std::thread b(write_y);std::thread c(read_x_then_y);std::thread d(read_y_then_x);a.join();b.join();c.join();d.join();// assert(z.load() != 0); // 5std::cout << z.load() << std::endl;}return 0;
}

memory_order_seq_cst 下,所有的操作会严格按照全序进行,因此每个线程的原子操作都是同步的。

程序的输出 z 最终将是 02,这取决于两个 read_* 线程的执行顺序。如果两个线程都能正确读取到 xy,则 z 会增加到 2。

四.总结

只有我们要极致提升性能的时候才有考虑原子操作进行提升性能 ,在绝大部分时候我们只需要使用互斥锁和条件变量即可满足服务器开发的需求

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

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

相关文章

Unet网络的Pytorch实现和matlab实现

文章目录 一、Unet网络简介1.1 输入图像1.2 编码器部分&#xff08;Contracting Path&#xff09;1.3 解码器部分&#xff08;Expanding Path&#xff09;1.4 最后一层&#xff08;输出&#xff09;1.5 跳跃连接&#xff08;Skip Connections&#xff09; 二、Unet网络的Pytorc…

记录一次JVM调优过程1

如何通过jmap 诊断&#xff0c;服务运行一段时间后内存使用量飙升的问题 通过 jmap 诊断服务运行一段时间后内存使用量飙升的问题&#xff0c;需结合堆转储分析、对象分布统计及工具链配合。以下是具体操作步骤和关键方法&#xff1a; 一、实时监控与初步分析 获取进程 PID 使…

接口自动化学习五:mock工具使用

Moco简介&#xff1a; Mock是一个简单搭建模拟服务器的框架&#xff0c;可以用来模拟http、https、socket等协议。 原理&#xff1a; Mock会根据一些配置&#xff0c;启动一个真正的HTTP服务&#xff08;会监听本地的某个端口&#xff09;,当发起的请求满足某个条件时&#xf…

若依 前后端部署

后端&#xff1a;直接把代码从gitee上拉去到本地目录 (https://gitee.com/y_project/RuoYi-Vue ) 注意下redis连接时password改auth 后端启动成功 前端&#xff1a;运行前首先确保安装了node环境&#xff0c;随后执行&#xff1a; &#xff01;&#xff01;一定要用管理员权限…

Adaptive AUTOSAR 状态管理和转换——ActionItemList

在AUTOSAR的状态转换管理(STM,State Transition Manager) 框架中,ActionItemList 是连接 状态机状态(State Machine State) 与 功能组状态(Function Group States) 的核心配置元素。 以下是其关系与作用的详细解释: 1. 核心概念 状态机状态(State Machine State) 表…

一个基于ragflow的工业文档智能解析和问答系统

工业复杂文档解析系统 一个基于ragflow的工业文档智能解析和问答系统,支持多种文档格式的解析、知识库管理和智能问答功能。 系统功能 1. 文档管理 支持多种格式文档上传(PDF、Word、Excel、PPT、图片等)文档自动解析和分块处理实时处理进度显示文档解析结果预览批量文档…

linux系统下如何提交git和调试

我们默认的ubuntu20.04镜像是没有Git提交的工具&#xff0c;我们需要配置安装包。 安装和更新git的命令 sudo apt update //用于更新软件包索引sudo apt install git //用于安装git版本控制工具 git --version //检查git版本,确认是否安装成功 随便进入linux系统下的一…

轻量级爬虫框架Feapder入门:快速搭建企业级数据管道

一、目标与前置知识 1. 目标概述 本教程的主要目标是&#xff1a; 介绍轻量级爬虫框架 Feapder 的基本使用方式。快速搭建一个采集豆瓣电影数据的爬虫&#xff0c;通过电影名称查找对应的电影详情页并提取相关信息&#xff08;电影名称、导演、演员、剧情简介、评分&#xf…

spring mvc的拦截器HandlerInterceptor 接口详解

HandlerInterceptor 接口详解 1. 接口方法说明 方法作用执行时机返回值/注意事项preHandle请求处理前拦截在控制器方法执行前调用返回 false 中断后续流程&#xff1b;返回 true 继续执行postHandle控制器方法执行后拦截在控制器方法返回结果后&#xff0c;视图渲染前调用无返…

数据可视化 —— 柱形图应用(大全)

一、案例一&#xff1a;单柱形图 1.导入库 import matplotlib.pyplot as plt import pandas as pd import numpy as np 2.给窗口名称和画布大小 plt.figure(num单柱形图, figsize(6, 4), facecolorw) 3.定义x、y轴的数据 # range(0-4) x np.arange(5) # 创建数组 y1 np.a…

apijson 快速上手

apijson是强大的工具&#xff0c;简化了CRUD的操作&#xff0c;只要有数据库表&#xff0c;就能自动生成RESTFUL接口。但初次上手也是摸索了很长时间&#xff0c;尤其是部署与使用上&#xff0c;这里尝试以初学者角度来说下&#xff1a; 一、好处 1、对于简单的应用&#xff…

V4L2杂谈

V4L2的开发手册 在做v4l2的开发的时候&#xff0c; 可以使用v4l2-ctl命令协助调试和软件开发。关于linux多媒体开发可以参考链接&#xff1a;https://www.linuxtv.org/wiki/index.php/Main_Page关于v4l2的api接口开发可以参考&#xff1a;https://linuxtv.org/docs.php在linux…

(五)深入了解AVFoundation-播放:多音轨、字幕、倍速播放与横竖屏切换

引言 在之前的博客中&#xff0c;我们已经实现了一个相对完整的播放器&#xff0c;具备了基本功能&#xff0c;如播放、暂停、播放进度显示和拖拽快进等。这为我们提供了一个坚实的基础。接下来&#xff0c;我们将进一步扩展播放器的功能&#xff0c;使其更具灵活性和实用性&a…

3ds Max 2016的版本怎么处理 按键输入被主程序截断 C#winform窗体接受不到英文输入

3ds Max 2016的版本怎么处理 按键输入被主程序截断 C#winform窗体接受不到英文输入 如果窗体失去焦点应该取消 全局监听事件 解决方案&#xff1a;在窗体失去焦点时取消全局键盘钩子 为了确保 WinForms 窗体失去焦点时不再拦截键盘事件&#xff08;避免影响 3ds Max 或其他程…

华为手机或平板与电脑实现文件共享

1.手机或平板与电脑在同一个网络 2.打开手机或平板端&#xff0c;设置---更多连接----快分享或华为分享打开此功能-----开启共享至电脑 3.打开电脑&#xff0c;网络中就可看到手机端分享的用户名称 4. 登陆就可访问手机 5.常见问题 5.1 电脑未发现本机 5.2 修改了访问密码后再…

elemenPlus中,如何去掉el-input中 文本域 textarea自带的边框和角标

1、去掉角标 :deep(.el-textarea__inner) {resize: none !important; // 去除右下角图标 }2、去除边框&#xff0c;并自定义背景色 <el-inputref"textareaRef"v-model"tempContent":style"{--el-border-color: rgba(255,255,255,0.0),--el-input-…

xv6-labs-2024 lab2

lab-2 0. 前置 课程记录 操作系统的隔离性&#xff0c;举例说明就是&#xff0c;当我们的shell&#xff0c;或者qq挂掉了&#xff0c;我们不希望因为他&#xff0c;去影响其他的进程&#xff0c;所以在不同的应用程序之间&#xff0c;需要有隔离性&#xff0c;并且&#xff0…

MCU控制4G模组(标准AT命令),CatM的最大速率?

根据3GPP标准&#xff0c;Cat M1的上行峰值速率大约是1 Mbps&#xff0c;下行大约是1 Mbps。但实际速率会受到多种因素影响&#xff0c;比如网络条件、信号强度、模块配置等。 考虑使用AT命令时的开销。每次发送数据都需要通过AT命令&#xff0c;比如ATQISEND&#xff0c;会引…

JavaScript(JS进阶)

目录 00闭包 01函数进阶 02解构赋值 03通过forEach方法遍历数组 04深入对象 05内置构造函数 06原型 00闭包 <!-- 闭包 --><html><body><script>// 定义&#xff1a;闭包内层函数&#xff08;匿名函数&#xff09;外层函数的变量&#xff08;s&…

6.1es新特性解构赋值

解构赋值是 ES6&#xff08;ECMAScript 2015&#xff09;引入的语法&#xff0c;通过模式匹配从数组或对象中提取值并赋值给变量。&#xff1a; 功能实现 数组解构&#xff1a;按位置匹配值&#xff0c;如 let [a, b] [1, 2]。对象解构&#xff1a;按属性名匹配值&#xff0c;…