C++并发编程-14. 利用栅栏实现同步

前文我们通过原子操作实战实现了无锁队列,今天完善一下无锁的原子操作剩余的知识,包括Relaese和Acquire内存序在什么情况下是存在危险的,以及我们可以利用栅栏机制实现同步等等。

线程可见顺序

  • 我们提到过除了memory_order_seq_cst顺序,其他的顺序都不能保证原子变量修改的值在其他多线程中看到的顺序是一致的。

但是可以通过同步机制保证一个线程对原子变量的修改对另一个原子变量可见。通过“Syncronizes With” 的方式达到先行的效果。

但是我们说的先行是指 “A Syncronizes With B ”, 如果A 的结果被B读取,则A 先行于B。

有时候我们线程1对A的store操作采用release内存序,而线程2对B的load采用acquire内存序,并不能保证A 一定比 B先执行。因为两个线程并行执行无法确定先后顺序,我们指的先行不过是说如果B读取了A操作的结果,则称A先行于B。

我们看下面的一段案例

#include <iostream>
#include <atomic>
#include <thread>
#include <cassert>
std::atomic<bool> x, y;
std::atomic<int> z;
void write_x()
{x.store(true, std::memory_order_release); //1
}
void write_y()
{y.store(true, std::memory_order_release); //2
}
void read_x_then_y()
{while (!x.load(std::memory_order_acquire));if (y.load(std::memory_order_acquire))   //3++z;
}
void read_y_then_x()
{while (!y.load(std::memory_order_acquire));if (x.load(std::memory_order_acquire))   //4++z;
}
// 我们写一个函数测试,函数TestAR中初始化x和y为false, 启动4个线程a,b,c,d,分别执行write_x, write_y, read_x_then_y, read_y_then_x.
void TestAR()
{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 value is " << z.load() << std::endl;
}

有的读者可能会觉5处的断言不会被触发,他们认为c和d肯定会有一个线程对z执行++操作。他们的思路是这样的。
1 如果c线程执行read_x_then_y没有对z执行加加操作,那么说明c线程读取的x值为true, y值为false。
2 之后d线程读取时,如果保证执行到4处说明y为true,等d线程执行4处代码时x必然为true。
3 他们的理解是如果x先被store为true,y后被store为true,c线程看到y为false时x已经为true了,那么d线程y为true时x也早就为true了,所以z一定会执行加加操作。

上述理解是不正确的,我们提到过即便是releas和acquire顺序也不能保证多个线程看到的一个变量的值是一致的,更不能保证看到的多个变量的值是一致的。

变量x和y的载入操作3和4有可能都读取false值(与宽松次序的情况一样),因此有可能令断言触发错误。变量x和y分别由不同线程写出,所以两个释放操作都不会影响到对方线程。

看下图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

即线程a执行了,但是线程d没有看见
线程b执行了,但是线程c没有看见

栅栏

有时候我们可以通过栅栏保证指令编排顺序。

看下面一段代码

#include <atomic>
#include <thread>
#include <assert.h>
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;
}
int main()
{x=false;y=false;z=0;std::thread a(write_x_then_y);std::thread b(read_y_then_x);a.join();b.join();assert(z.load()!=0);  //5
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

如何选择旅游科技行业云ERP?Oracle NetSuite助力汇智国际数智化升级

2025年4月21日&#xff0c;汇智国际旅游发展有限公司&#xff08;以下简称汇智国际&#xff09;携手 Oracle NetSuite与Hitpoint Cloud &#xff0c;共同参与了汇智国际 Oracle NetSuite 云ERP 项目启动会。 本次会议标志着汇智国际在数字化转型道路上迈出了坚实而关键的一步&…

深度学习零基础入门(3)-图像与神经网络

好久不见~我又回来了 这一节我们来讲一讲图像在计算机中的本质&#xff0c;以及全连接神经网络的缺陷&#xff0c;进而引出卷积神经网络一、图像在计算机中的本质 不知道你有没有学过数据结构&#xff0c;在讲这一部分的时候对数组进行了扩展&#xff0c;讲到了广义表和压缩矩阵…

http性能测试命令ab

在 Linux系统中&#xff0c; ab&#xff08; ApacheBench&#xff09;是一个用于 测试HTTP服务器性能的 工具。它是 Apache HTTP服务器项目的 一部分&#xff0c;专门设计用来模拟 多个用户对 服务器发起 并发请求&#xff0c;从而 评估服务器的 负载能力和 响应时间其中&#…

从0开始学习R语言--Day50--ROC曲线

对于已经拟合好的生存模型&#xff0c;我们一般会直接用ROC去评判一下整体的水平&#xff0c;因为很多时候阈值都是我们人为根据实际情况去设定的&#xff0c;这种微调的细节都是在整体模型的拟合程度确定下来后再做的工作。ROC曲线可以提供给我们模型对于二分类变量的区分能力…

从Hyperliquid到AILiquid:一场从极致性能到策略智能的迭代

在Hyperliquid以极致性能引爆链上衍生品交易热潮之后&#xff0c;DeFi市场正迎来新一轮的范式转变。作为AI原生的下一代交易平台&#xff0c;AILiquid正式上线并引发市场广泛关注。该平台不仅保留了高频低延迟的交易体验&#xff0c;更通过AI撮合引擎与链上风险控制系统&#x…

磁悬浮轴承转子不平衡质量控制:陷波滤波器深度解析

在磁悬浮轴承高速旋转的世界里&#xff0c;不平衡质量如同一个无形的幽灵&#xff0c;引发危险的同步振动&#xff0c;而陷波滤波器&#xff0c;正是精准捕获并消除这个幽灵的“电磁猎手”。本文将深入剖析其核心原理与实战设计。引言&#xff1a;同步振动的致命诱惑磁悬浮轴承…

Oracle 数据库常见等待事件参数详解

在 Oracle 数据库的性能诊断与优化中&#xff0c;等待事件是重要的分析依据&#xff0c;而理解等待事件的参数则是深入排查问题的基础。本文将结合 Oracle 官方文档&#xff0c;对数据库中常见的等待事件参数进行详细解析&#xff0c;帮助数据库管理员和开发人员更好地解读等待…

STM32中的CAN总线详解:从原理到实战

前言&#xff1a;为什么CAN总线是嵌入式通信的"硬通货"&#xff1f; 在嵌入式通信领域&#xff0c;CAN&#xff08;Controller Area Network&#xff09;总线凭借其高可靠性、实时性和多节点通信能力&#xff0c;成为汽车电子、工业控制、智能设备等领域的"标配…

【鸿蒙HarmonyOS】鸿蒙app开发入门到实战教程(二):封装自定义可复用组件

组件的可复用性&#xff0c;对我们开发的app质量影响很大&#xff0c;看看鸿蒙中如何封装这种组件 实现效果代码实现 局部封装 Builder titleBuilder(title:string 默认标题) {// Builder装饰此函数&#xff0c;使其能以链式调用的方式配置并构建Text组件Row(){Text(title).fo…

Volo-HTTP 0.4.0发布:正式支持 HTTP/2,客户端易用性大幅提升!

&#x1f916; VOLO简介 Volo 是由字节跳动服务框架团队开源的一款高性能、易用的 Rust RPC 框架。 Volo 框架自身开销极低&#xff0c;并提供了命令行工具与灵活的中间件设计&#xff0c;让开发者可以轻松上手&#xff0c;享受 Rust 带来的开发乐趣。 本文介绍自 Volo-HTTP 0…

HTTP相关知识

文章目录一、基础特性与规范二、页面元素与布局三、交互与表单四、网络通信基础流程&#xff08;以浏览器访问网页为例&#xff09;五、配套技术与工具六、知识关联图&#xff08;简化版&#xff09;一、基础特性与规范 技术定位&#xff1a;HTML 是前端技术栈的核心标记语言&…

机器人-组成结构

目录 一、发展历程 二、软件硬件算法深读耦合 感知 - 决策 - 执行 1.机械系统&#xff1a; 2.驱动系统&#xff1a; 3.感知系统&#xff1a; 4.控制系统&#xff1a; 5.决策/智能系统&#xff1a; 6.电源系统&#xff1a; 7.总结 一、发展历程 国际标准化组织(ISO)对…

pycharm结构查看器

v表示整个文件中定义的变量&#xff0c;c是类灰色部分是继承的父类的&#xff0c;明亮的是定义的&#xff0c;其中m表示定义的函数&#xff0c;f表示

AdsPower 功能详解 | 应用中心使用指南:插件统一管理更高效、更安全!

当你使用 AdsPower 管理多个浏览器环境时&#xff0c;插件的统一配置就变得尤为重要。而「应用中心」正是帮助你集中管理浏览器插件的功能入口&#xff0c;搭配浏览器环境使用&#xff0c;可以让账号操作更便捷、团队协作更高效。这篇教程将带你快速上手 AdsPower 应用中心的核…

回归预测 | MATLAB实现DBO-BP蜣螂算法优化BP神经网络多输入单输出回归预测

回归预测 | MATLAB实现DBO-BP蜣螂算法优化BP神经网络多输入单输出回归预测 目录 回归预测 | MATLAB实现DBO-BP蜣螂算法优化BP神经网络多输入单输出回归预测 预测效果 基本介绍 主要功能 逻辑关联与算法流程 1. 数据准备 2. DBO优化BP参数 3. BP神经网络构建 4. 预测与评估 运行…

Lsposed/Xposed

1.环境 1.1 xposed: 安卓8以下使用 下载并安装xposed installer&#xff0c;模拟器需勾选设置-共享磁盘。 若提示未激活&#xff0c;需要下载sdk sdk下载地址 放置目录 /sdcard/Android/data/de.robv.android.xposed.installer/cache/downloads/framework/文件权限设置 777 …

3D工业相机是什么?如何选择和使用它?

工业自动化越来越深入&#xff0c;3D成像技术&#xff08;3D工业相机&#xff09;在工业生产中越来越重要。这篇文章就来说说3D工业相机的技术原理、具体能应用在哪以及怎么选3D相机&#xff0c;给大家做个参考。一、 技术定义与核心特点3D工业相机&#xff0c;简单说就是一种特…

有哪些好用的原型设计软件?墨刀、Axure等测评对比

下面是几款常用原型设计软件的简介和对比&#xff0c;重点对墨刀和Axure进行了测评分析&#xff0c;帮助你根据需求做出选择。&#x1f4a1;常见原型设计软件一览工具名称适合人群平台支持是否协作是否支持交互墨刀&#xff08;MockingBot&#xff09;产品经理/团队协作Web、Wi…

二叉树思想草稿

二叉树解体两种思路 是否可以通过遍历一遍二叉树得到答案&#xff1f; 用一个traverse函数配合外部变量实现遍历的思维模式 是否可以定义一个递归函数&#xff0c;通过子树的答案推导出原问题的答案&#xff1f; 递归三部曲&#xff1a; 函数定义&#xff0c;参数&#xff0c;返…

如何区分Bug是前端问题还是后端问题?

在软件测试中,精准定位Bug的归属(前端 or 后端)是高效协作的关键。以下是系统化的排查方法,结合技术细节和实战技巧: 1. 核心判断逻辑 「数据 vs 展示」二分法: 后端问题:数据本身错误(API返回错误数据/逻辑错误/数据库问题) 前端问题:数据正确但展示异常(UI渲染错…