是否应该将内存栅栏与互斥获取交换循环(或队列获取加载循环)结合起来,还是应该避免?

2023-11-29

假设重复获取操作,尝试加载或交换值,直到观察到的值是所需值。

让我们来cppreference 原子标志示例作为起点:

void f(int n)
{
    for (int cnt = 0; cnt < 100; ++cnt) {
        while (lock.test_and_set(std::memory_order_acquire))  // acquire lock
             ; // spin
        std::cout << "Output from thread " << n << '\n';
        lock.clear(std::memory_order_release);               // release lock
    }
}

现在让我们考虑一下这种旋转的增强。两个著名的是:

  • 不要永远旋转,而是在某个时刻进入操作系统等待;
  • 使用指令,例如pause or yield而不是无操作旋转。

我可以想到第三种,我想知道它是否有意义。 我们可以用std::atomic_thread_fence对于获取语义:

void f(int n)
{
    for (int cnt = 0; cnt < 100; ++cnt) {
        while (lock.test_and_set(std::memory_order_relaxed))  // acquire lock
             ; // spin
        std::atomic_thread_fence(std::memory_order_acquire);  // acquire fence
        std::cout << "Output from thread " << n << '\n';
        lock.clear(std::memory_order_release);               // release lock
    }
}

我预计对于 x86 来说这不会有任何变化。

我在想:

  • 在存在差异的平台(ARM)上,此更改是否有好处或缺点?
  • 是否会干扰使用或不使用的决定yield操作说明?

我不仅感兴趣atomic_flag::clear / atomic_flag::test_and_set一对,我也感兴趣atomic<uint32_t>::store / atomic<uint32_t>::load pair.


更改为松弛负载可能是有意义的:

void f(int n)
{
    for (int cnt = 0; cnt < 100; ++cnt) {
        while (lock.test_and_set(std::memory_order_acquire))  // acquire lock
             while (lock.test(std::memory_order_relaxed))
                 YieldProcessor(); // spin
        std::cout << "Output from thread " << n << '\n';
        lock.clear(std::memory_order_release);               // release lock
    }
}

是的,避免失败重试路径内的获取障碍的总体想法可能是有用的,尽管如果您只是旋转,则失败情况下的性能几乎不相关。pause or yield节省电力。在 x86 上,pause还提高了 SMT 友好性,并避免在另一个核心修改了您正在旋转的内存位置后离开循环时内存顺序错误推测。

但这就是为什么 CAS 有单独的memory_order成功和失败的参数。宽松的失败可以让编译器仅在离开循环路径上设置障碍。

atomic_flag test_and_set但没有这个选项。手动执行此操作可能会损害像 AArch64 这样的 ISA,这些 ISA 本来可以获取 RMW 并避免显式的栅栏指令。 (例如与ldarb)

Godbolt:原始循环与lock.test_and_set(std::memory_order_acquire):

# AArch64 gcc8.2 -O3
.L6:                            # do{
    ldaxrb  w0, [x19]           # acquire load-exclusive
    stxrb   w1, w20, [x19]      # relaxed store-exclusive
    cbnz    w1, .L6            # LL/SC failure retry
    tst     w0, 255
    bne     .L6             # }while(old value was != 0)
  ... no barrier after this

(是的,它看起来像是一个错过的优化,它只测试低 8 位tst而不仅仅是cbnz w1, .L6)

while(宽松的RMW) +std::atomic_thread_fence(std::memory_order_acquire);

.L14:                          # do {
    ldxrb   w0, [x19]             # relaxed load-exclusive
    stxrb   w1, w20, [x19]        # relaxed store-exclusive
    cbnz    w1, .L14             # LL/SC retry
    tst     w0, 255
    bne     .L14               # }while(old value was != 0)
    dmb     ishld         #### Acquire fence
   ...

对于 32 位 ARMv8 来说更糟 where dmb ishld不可用,或者编译器不使用它。你会得到一个dmb ish全屏障。


Or with -march=armv8.1-a

.L2:
    swpab   w20, w0, [x19]
    tst     w0, 255
    bne     .L2
    mov     x2, 19
  ...

vs.

.L9:
    swpb    w20, w0, [x19]
    tst     w0, 255
    bne     .L9
    dmb     ishld                   # acquire barrier (load ordering)
    mov     x2, 19
...
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

是否应该将内存栅栏与互斥获取交换循环(或队列获取加载循环)结合起来,还是应该避免? 的相关文章

  • 为 ARM 交叉编译 zlib

    我尝试为arm poky linux gnueabi交叉编译zlib 但启动 make 时出现错误 zlib 1 2 11 AR HOST ar CC HOST gcc RANLIB HOST ranlib configure prefix
  • 现代缓存中的方式预测

    我们知道 就缓存命中时间而言 直接映射缓存优于集合关联缓存 因为不涉及特定标签的搜索 另一方面 组关联缓存通常比直接映射缓存具有更好的命中率 我读到 现代处理器试图通过使用一种称为路径预测的技术来结合两者的优点 他们预测给定集合中最有可能发
  • 有没有办法在 Xcode 4 中为 ARM 而不是 Thumb 进行编译?

    如果有很多浮点运算正在进行 Apple 建议针对 ARM 进行编译 而不是针对拇指进行编译 我的整个应用程序几乎是一个大型浮点运算 iOS 应用程序开发工作流程指南中是这样说的 iOS 设备支持两种指令集 ARM 和 Thumb Xcode
  • 为什么 i2c_smbus 函数不可用? (I2C——嵌入式Linux)

    有很多参考使用i2c smbus 开发嵌入式 Linux 软件时在 I2C 总线上进行通信的函数 什么时候i2c smbus函数如i2c smbus read word data在软件项目中引用了 ARM8 处理器错误 例如 i2c smb
  • Verilog 双向握手示例

    我正在完成一个项目 要求是处理器内部功能单元之间的双向握手 我知道它是什么 但是有没有任何 标准 或一个简单的例子 我唯一能想到的就是两个单元之间 当它们之间有一条数据线并且当 X 发送到 Y 时 会给出一个单独的 发送 信号 当 Y 接收
  • 在 Intel 机器上构建 Apple Silicon 二进制文件

    如何在 macOS 11 Intel 上编译 C 项目以在 Silicon 上运行 我当前的构建脚本很简单 configure make sudo make install 我尝试过使用 host and target标志与aarch64
  • AOSP 的“午餐”组合是什么意思?我需要选择什么?

    我是 Android 设备 ROM 开发的新手 无论如何 我现在正在为具有 64 位处理器的中国设备构建 AOSP 我按照 source android com 上的菜单进行操作 当我运行 午餐 命令时 终端显示 午餐菜单 选择一个组合 我
  • 如何在 icarus verilog 中包含文件?

    我知道基本的 include filename v 命令 但是 我试图包含另一个文件夹中的模块 现在 该模块还包括同一文件夹中存在的其他模块 但是 当我尝试在最顶层运行该模块时 出现错误 C Users Dell Desktop MIPS
  • 为什么 GCC 交叉编译不构建“crti.o”?

    在尝试为arm构建gcc 4 x x交叉编译器时 我陷入了缺失的困境crti o文件在 BUILD DIR gcc子目录 An strace在顶层Makefile表明编译后的xgcc正在调用交联器ld with crti o 作为一个论点
  • 使用 NEON 内在函数除以浮点数

    我当时正在处理四个像素的图像 这是在armv7对于 Android 应用程序 我想分一个float32x4 t向量由另一个向量组成 但其中的数字与大约不同0 7 to 3 85 在我看来 除法的唯一方法是使用右移 但这是针对一个数字2 n
  • arm-linux-gnueabi 编译器选项

    我在用 ARM Linux gnueabi gcc在 Linux 中为 ARM 处理器编译 C 程序 但是 我不确定它编译的默认 ARM 模式是什么 例如 对于 C 代码 test c unsigned int main return 0x
  • GCC C++ (ARM) 和指向结构体字段的 const 指针

    假设有一个简单的测试代码 typedef struct int first int second int third type t define ADDRESS 0x12345678 define REGISTER type t ADDRE
  • arm64和armhf有什么区别?

    Raspberry Pi Type 3 具有 64 位 CPU 但其架构不是arm64 but armhf 有什么区别arm64 and armhf armhf代表 arm hard float 是给定的名称Debian 端口 https
  • 交叉编译armv5,但它创建v7二进制文件

    我设法为arm926ej s创建了一个目标文件我在 qemu 上使用 Debian Arm arm linux gnueabi gcc 4 4 static O c mcpu arm926ej s hello c o hello root
  • Intel:序列化指令和分支预测

    英特尔架构开发人员手册 http www intel com content www us en architecture and technology 64 ia 32 architectures software developer v
  • ARM Cortex-M3 启动代码

    我试图了解 STM32 微控制器的 Keil realview v4 附带的初始化代码是如何工作的 具体来说 我试图了解堆栈是如何初始化的 In the 文档 http infocenter arm com help index jsp t
  • 让 TensorFlow 在 ARM Mac 上使用 GPU

    我已经安装了TensorFlow在 M1 上 ARM Mac 根据这些说明 https github com apple tensorflow macos issues 153 一切正常 然而 模型训练正在进行CPU 如何将培训切换到GPU
  • 对将英特尔傲腾 DC SSD 用作 IMDT 的额外 RAM 感到困惑吗? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我对英特尔傲腾 DC 有点困惑 我希望我的 Optane DC 能够同时充当 DRAM 和存储 一方面 我了解到只有 英特尔傲腾 DC 持
  • 哪些 GCC 优化标志对二进制大小影响最大?

    我正在使用 GCC 为 ARM 开发 C 我遇到了一个问题 我没有启用优化 我无法创建二进制文件 ELF https en wikipedia org wiki Executable and Linkable Format 对于我的代码 因
  • 原子的 C++ 内存屏障

    在这方面我是个新手 谁能提供以下内存屏障之间差异的简化解释 窗户MemoryBarrier 围栏 mm mfence 内联汇编asm volatile memory 内在的 ReadWriteBarrier 如果没有简单的解释 一些好文章或

随机推荐

  • 使用 EclipseLink 和 Hibernate (JPA2.1) 生成架构 - @ForeignKey 被忽略

    我正在测试 JPA2 1 和新的 模式生成 功能 为此 我在 HyperSQL 数据库下测试了两种实现 EclipseLink 2 5 2 M1 是参考实现 休眠4 3 我对实现没有任何偏好 甚至对性能也没有偏好 我测试了 EclipseL
  • Tomcat 7 更新后继续使用旧的 jsp

    我们 我公司的人员 不久前为 Tomcat 创建了一个应用程序 它使用 servlet 和 jsp 作为 GUI 我们刚刚完成了一次更新 其中一个 jsp 发生了很大的变化 但是 当我们在一台计算机上替换 war 文件时 它会继续使用旧的
  • 在 Magento 1.6.2 中登录/注销时如何从 top.links 中删除链接

    我进行了很好的搜索并找到了customer logged in and customer logged out标签 但我无法让它们正常工作 我确信这是我对它们的误解 我的目标是隐藏区块中的登录 帐户和结账链接top links当用户处于no
  • R(https) 中 getSymbols 函数使用错误 [关闭]

    Closed 这个问题是无法重现或由拼写错误引起 目前不接受答案 Running library quantmod getSymbols BSESN src yahoo 产生以下错误消息 Error in download file pas
  • 通过cmd上传和更新谷歌驱动器中的文件[关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 目前不接受答案 是否有任何脚本可以让 Google Drive 每天自动上传 转换和更新 csv 文件 我按照 Google 站点上的 JDBC 上的脚本进行操作
  • 为什么 Stream Parallel() 不使用所有可用线程?

    我尝试跑100Sleep使用 Java8 1 8 0 172 Stream parallel 并行任务在自定义 ForkJoinPool 内提交 有 100 多个可用线程 每个任务都会sleep1秒 鉴于 100 个睡眠可以并行完成 我预计
  • HTML 选择。 Select2 + ng-click = 不起作用?

    我在用AngularJS and Select2创建一个漂亮的下拉菜单 我已经包括了ng click在 选择标签的 选项标签中 但是 ng click 在处于Select2
  • 了解 Dart 1.11 的新appendHTML清理

    我刚刚升级到 Dart 1 11 我不太明白发生了什么 appendHTML 我有一个非常大的项目 使用 dart 和 appendHTML 经常使用 我已经在这个应用程序上工作了一年多了 但现在没有任何效果了 我的控制台看起来像这样 Re
  • BUG:IIS7 托管请求

    我不知道是否也应该将这个问题发布到 ServerFault 因为它是关于 IIS 配置的 在 IIS7 中 我们可以通过以下方式告诉模块运行托管内容 从而加快静态内容服务
  • 在 Microsoft Access 2010 表单和报告中显示多个附件

    最初 我很高兴在 Access 2010 中发现附件字段 这个功能在美学上让我内心的数据库纯粹主义者感到厌烦 但我内心的懒惰在这里负责 从表面上看 它确实看起来可以使一个我当前的项目更容易 更简单 令人高兴的是 它会在表单和报告上自动显示图
  • Objective-C:如何找到数组中最常见的字符串?

    我有一个来自在线数据库的字符串数组 我试图确定最常用的单词 数组内的值会有所不同 但我想检查我正在使用的任何集合或单词中最常见的单词 如果理论上我有以下数组 NSArray stringArray NSArray arrayWithObje
  • 防止执行“继承的”信号处理程序

    当许多派生组件频繁使用该功能时 在 基本 组件中定义信号处理程序非常漂亮 但是 在 QML 中 在派生组件中安装新的处理程序does not替换原来的处理程序 它只是堆叠在它的上面 由于处理程序对于每个信号来说并不是唯一的 它们只是连接 并
  • SQLCLR 程序集部署失败,因为程序集验证失败

    万一其他人遇到这个问题 错误 SQL72014 Net SqlClient 数据提供程序 创建程序集 程序集 Assembly Name 失败 因为程序集 Assembly Name 验证失败 检查引用的程序集是否是最新的 并受信任 对于
  • 设置会话文化

    我的应用程序的每个用户都会选择他们的国家 地区 然后将其存储在 cookie 中并存储以供以后请求 一切正常 但我需要在会话开始时设置文化 我目前正在尝试将 web config 中的区域性设置为 en GB 然后使用 Global asa
  • 如何指定整个路由器的依赖关系?

    class User BaseModel name str token str fake db User name foo token a1 User name bar token a2 async def get user by toke
  • 附加到 NSTextView

    我有一个NSTask 与NSPipe设置 在后台运行 我想在内容进入时输出它们NSTextView output 我正在使用的代码是 NSMutableAttributedString str NSMutableAttributedStri
  • 使用asp.net mvc下载文件

    我尝试使用下面的代码 但这没有用 public FileResult download string path return File path application pdf Server UrlEncode path 我的 Ajax 代
  • 使用数组作为自动过滤条件

    我有以下代码 它将根据第一列中的条件删除行 Sub Strip Dim rng As Range With ActiveSheet Columns I AutoFilter Field 1 Criteria1 70 79 VisibleDr
  • 基于 WIX 的安装程序如何为 32 位和 64 位 Windows 操作系统进行 COM 注册?

    我有一个长期存在的安装程序 它使用RegistryValue来设置 Net COM服务器 安装程序是 32 位的 我希望也为 64 位操作系统设置注册表设置 我的研究表明我需要一个单独的 64 位安装程序来实现此目的 好吧 我怎样才能有一个
  • 是否应该将内存栅栏与互斥获取交换循环(或队列获取加载循环)结合起来,还是应该避免?

    假设重复获取操作 尝试加载或交换值 直到观察到的值是所需值 让我们来cppreference 原子标志示例作为起点 void f int n for int cnt 0 cnt lt 100 cnt while lock test and