C11 中的内存顺序消耗使用情况

2023-12-04

我读到了关于带有依赖性关系和依赖顺序先于在其定义中使用 15.1.2.4(p16):

评价A在评估之前是依存顺序的B if:

A对原子对象执行释放操作M,并且,在另一个 线,B执行消费操作M并读取写入的值 由释放序列中的任何副作用引起A, or

- 一些评估X, A之前是依赖顺序的X and X具有依赖性B.

所以我尝试制作一个可能有用的示例。就这个:

static _Atomic int i;

void *produce(void *ptr){
    int int_value = *((int *) ptr);
    atomic_store_explicit(&i, int_value, memory_order_release);
    return NULL;
}

void *consume(void *ignored){
    int int_value = atomic_load_explicit(&i, memory_order_consume);
    int new_int_value = int_value + 42;
    printf("Consumed = %d\n", new_int_value);
}

int main(int args, const char *argv[]){
    int int_value = 123123;
    pthread_t t2;
    pthread_create(&t2, NULL, &produce, &int_value);

    pthread_t t1;
    pthread_create(&t1, NULL, &consume, NULL);

    sleep(1000);
}

在函数中void *consume(void*) the int_value带有依赖关系new_int_value so if atomic_load_explicit(&i, memory_order_consume);读取某些人写入的值atomic_store_explicit(&i, int_value, memory_order_release); then new_int_value计算依赖顺序先于 the atomic_store_explicit(&i, int_value, memory_order_release);.

但是 dependency-ordered-before 能给我们带来什么有用的东西呢?

我目前认为memory_order_consume很可能被替换为memory_order_acquire不会引起任何数据竞争...


consume is cheaper than acquire. All CPUs (except DEC Alpha AXP's famously weak memory model1) do it for free, unlike acquire. (Except on x86 and SPARC-TSO, where the hardware has acq/rel memory ordering without extra barriers or special instructions.)

在 ARM/AArch64/PowerPC/MIPS/etc 弱有序 ISA 上,consume and relaxed是唯一不需要任何额外障碍的订单,只需普通的廉价加载指令。即所有 asm 加载指令(至少)consume负载,除了 Alpha 上。acquire需要 LoadStore 和 LoadLoad 排序,这是比全屏障更便宜的屏障指令seq_cst,但仍然比没有贵。

mo_consume就好像acquire仅适用于数据依赖于消耗负载的负载. e.g. float *array = atomic_ld(&shared, mo_consume);,然后访问任意array[i]如果生产者存储了缓冲区并且then used a mo_releasestore 将指针写入共享变量。但独立的加载/存储不必等待consume加载完成,并且可以在它之前发生,即使它们在程序顺序中出现得较晚。所以consume只订购最低限度的订单,不影响其他负载或商店。


(实现支持基本上是免费的consume大多数 CPU 设计的硬件语义,因为 OoO exec 无法打破真正的依赖关系,并且加载对指针具有数据依赖性,因此加载指针然后取消引用它本质上只是根据因果关系的性质对这两个加载进行排序。除非 CPU 进行价值预测或其他疯狂的事情。 值预测类似于分支预测,但猜测将加载什么值,而不是分支将走哪条路。

Alpha 必须做一些疯狂的事情,以使 CPU 能够在指针值真正加载之前实际加载数据,此时存储是按顺序完成且具有足够的屏障。

与存储不同的是,存储缓冲区可以在存储执行和提交到 L1d 缓存之间引入重新排序,通过从 L1d 缓存获取数据,负载变得“可见”execute,而不是当退休+最终提交时。所以订购 2 个负载。彼此实际上只是意味着按顺序执行这两个加载。由于数据之间存在相互依赖性,因果关系要求在没有值预测的 CPU 上这样做,并且在大多数架构上,ISA 规则确实特别要求这一点。因此,您不必在加载 + 使用 asm 中的指针之间使用屏障,例如用于遍历链表。)

也可以看看CPU 中的相关负载重新排序


但目前的编译器只是放弃并加强consume to acquire

...而不是尝试将 C 依赖项映射到 asmdata依赖关系(不会意外地破坏只有分支预测+推测执行可以绕过的控制依赖关系)。显然,对于编译器来说,跟踪它并确保它的安全是一个难题。

将 C 映射到 asm 并不简单,因为如果依赖项仅采用条件分支的形式,则 asm 规则不适用。所以很难定义 C 规则mo_consume仅以符合 asm ISA 规则中“携带依赖项”的方式传播依赖项。

所以是的,你是对的consume可以安全地替换为acquire,但你完全没有抓住要点。


ISAs with weak memory-ordering rules do have rules about which instructions carry a dependency. So even an instruction like ARM eor r0,r0 which unconditionally zeroes r0 is architecturally required to still carry a data dependency on the old value, unlike x86 where the xor eax,eax idiom is specially recognized as dependency-breaking2.

也可以看看http://preshing.com/20140709/the- Purpose-of-memory_order_consume-in-cpp11/

我还提到过mo_consume在回答中原子操作、std::atomic 和写入顺序.


脚注1:理论上实际上可以“违反因果关系”的少数 Alpha 模型没有进行价值预测,它们的存储缓存有不同的机制。我想我已经看到了关于它如何可能的更详细的解释,但是 Linus 关于它实际上是多么罕见的评论很有趣。

Linus Torvalds(Linux 首席开发人员),在 RealWorldTech 论坛帖子中

我想知道,你是自己在 Alpha 上看到非因果关系还是在手册中看到的?

我自己从未见过,我也不认为我曾经拥有过任何模型 访问实际上做到了。这实际上使得(缓慢的)人民币 指令非常烦人,因为这纯粹是缺点。

即使在实际上可以重新排序负载的 CPU 上,它也是如此 显然在实践中基本上不可能击中。这实际上是 非常讨厌。结果是“哎呀,我忘记了一个障碍,但是一切 十年来一直运行良好,但有三份奇怪的报告称“那不能” 发生“现场错误”之类的事情。弄清楚是什么 继续下去真是痛苦极了。

哪些型号实际上有它?他们究竟是怎么来到这里的?

我认为是 21264,我对它的到期时间有模糊的记忆 到分区缓存:即使原始 CPU 进行了两次写入 顺序(中间有一个 wmb),读取 CPU 最终可能会得到 第一次写入延迟(因为它进入的缓存分区是 忙于其他更新),并且会先读取第二个写入。如果 第二次写入是第一次写入的地址,然后它可以 遵循该指针,并且没有读屏障来同步 缓存分区,它可以看到旧的陈旧值。

但请注意“模糊记忆”。我可能把它与其他东西混淆了。 到目前为止,我实际上已经有近二十年没有使用过阿尔法了。你 可以从价值预测中得到非常相似的效果,但我不认为 任何 alpha 微架构都曾这样做过。

无论如何,肯定有 alpha 版本可以做到这一点 这不仅仅是纯粹的理论上的。

(RMB = Read Memory Barrier asm 指令,和/或 Linux 内核函数的名称rmb()它包装了实现这一目标所需的任何内联汇编。例如在 x86 上,只是编译时重新排序的障碍,asm("":::"memory")。我认为现代 Linux 在只需要数据依赖时设法避免获取障碍,与 C11/C++11 不同,但我忘记了。 Linux 仅可移植到少数编译器,并且这些编译器确实会注意支持 Linux 所依赖的内容,因此它们比 ISO C11 标准更容易编写出在实际 ISA 上运行的东西。)

也可以看看https://lkml.org/lkml/2012/2/1/521回复:Linux 的smp_read_barrier_depends()这在 Linux 中是必要的,只是因为 Alpha。 (但是来自汉斯·伯姆指出“编译器有时可以删除依赖项”,这就是为什么 C11memory_order_consume支持需要如此详尽以避免破损风险。因此smp_read_barrier_depends可能很脆弱。)


脚注2:x86 对所有加载进行排序,无论它们是否带有对指针的数据依赖性,因此它不需要保留“假”依赖性,并且使用可变长度指令集,它实际上将代码大小保存为xor eax,eax(2 个字节)代替mov eax,0(5 字节)。

So xor reg,reg自 8086 天早期起就成为标准习语,现在它已被识别并实际处理为mov,不依赖于旧值或 RAX。 (事实上more有效地比mov reg,0不仅仅是代码大小:在 x86 汇编中将寄存器设置为零的最佳方法是什么:xor、mov 或 and?)

但这对于 ARM 或大多数其他弱有序 ISA 来说是不可能的,就像我说的那样,他们实际上不允许这样做。

ldr r3, [something]       ; load r3 = mem
eor r0, r3,r3             ; r0 = r3^r3 = 0
ldr r4, [r1, r0]          ; load r4 = mem[r1+r0].  Ordered after the other load

需要注入依赖r0并订购负载r4负载后r3,即使加载地址r1+r0总是只是r1因为r3^r3 = 0. 但只有that加载,而不是所有其他后续加载;它不是获取障碍或获取负载。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C11 中的内存顺序消耗使用情况 的相关文章

  • 单元测试验证失败

    我正在运行我的单元测试PostMyModel路线 然而 在PostMyModel 我用的是线Validate
  • 如何在另一个应用程序中挂钩 api 调用

    我正在尝试挂钩另一个应用程序的 ExtTextOut 和 DrawTextExt GDI 方法调用 我知道我需要使用 GetProcAddress 来查找 gdi32 dll 中那些方法的地址 并用我的函数的地址覆盖我想要挂钩的进程中的地址
  • 在 Java 中创建 T 的新实例

    在C 中 我们可以定义一个泛型class A
  • 删除是如何工作的? [复制]

    这个问题在这里已经有答案了 可能的重复 C 编程 free 如何知道要释放多少 https stackoverflow com questions 1518711 c programming how does free know how m
  • linq 中使用字符串数组 c# 的 'orderby'

    假设我有一个这样的方法定义 public CustomerOrderData GetCustomerOrderData string CustomerIDs var query from a in db Customer join b in
  • 是否存在指向不同类型的指针具有不同大小的平台?

    C 标准允许指向不同类型的指针具有不同的大小 例如sizeof char sizeof int 是允许的 但是 它确实要求如果将指针转换为void 然后转换回其原始类型 它必须与其原始值进行比较 因此 从逻辑上来说 sizeof void
  • 为什么'enable_if'不能用于禁用这里声明

    include
  • 访问 ascx 文件中的母版页控件

    我有一个母版页文件 其中包含 2 个面板控件中的 2 个菜单 我还使用控件来检查用户是否登录并获取用户类型 根据我想要显示 隐藏面板的类型 控件本身不在母版页中引用 而是通过 CMS 系统动态引用 我想在用户控件中使用findcontrol
  • UI 函数在快速事件完成之前触发

    我有一个停靠在 Silverlight 应用程序中的 Web 浏览器框架 有时会在其上弹出全窗口 XAML Silverlight UI 元素 我已经或多或少修复了一个老问题 即 Web 框架的内容似乎与 Silverlight 内容不能很
  • 使用 C# 和 wpf 创建类似 Dock 的应用程序

    我需要创建一个与我们购买笔记本电脑时获得的应用程序类似的应用程序 仅当鼠标指针到达窗口顶部时它才可见 那么我怎样才能使用 C 4 0 来做到这一点呢 http www notebookcheck net uploads pics win2
  • 搜索实体的所有字段

    我正在尝试在客户数据库上实现 多功能框 类型的搜索 其中单个查询应尝试匹配客户的任何属性 这是一些示例数据来说明我想要实现的目标 FirstName LastName PhoneNumber ZipCode Mary Jane 12345
  • 从BackgroundWorker线程更新图像UI属性

    在我正在编写的 WPF 应用程序中 我有一个 TransformedBitmap 属性 该属性绑定到 UI 上的 Image 对象 每当我更改此属性时 图像就会更新 因此显示在屏幕上的图像也会更新 为了防止在检索下一张图像时 UI 冻结或变
  • Project Euler #8,我不明白我哪里出了问题[关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 我正在做项目欧拉第八题 https projecteuler net problem 8 其中我得到了这个大得离谱的数字 7316
  • Linux mremap 不释放旧映射?

    我需要一种方法将页面从一个虚拟地址范围复制到另一个虚拟地址范围 而无需实际复制数据 范围很大 延迟很重要 mremap 可以做到这一点 但问题是它也会删除旧的映射 由于我需要在多线程环境中执行此操作 因此我需要旧映射能够同时使用 因此稍后当
  • 逆向工程 ASP.NET Web 应用程序

    我有一个 ASP NET Web 应用程序 我没有源代码 该 bin 包含 10 个程序集和一个 compiled 文件 我在 App Code dll 上使用 Reflector 它向我显示了类和命名空间之类的东西 但它太混乱了 有没有什
  • 如何停止无限循环?

    我正在编写一个程序 该程序将计算三角形或正方形的面积 然后提示用户是否希望计算另一个 我的代码已经运行到可以计算任一形状的面积的程度 但随后不再继续执行代码的其余部分 例如 如果选择了正方形 则计算面积 然后返回到正方形边长的提示 我假设这
  • 在 C#.NET 中安全删除文件

    在我正在做的一个项目中 我想为用户提供 安全 删除文件的选项 例如 用随机位或 0 覆盖它 在 C NET 中是否有一种简单的方法可以做到这一点 效果如何 你可以调用系统内部删除 http technet microsoft com en
  • 如何在 winforms 应用程序的主屏幕显示之前显示欢迎屏幕?

    我想在应用程序启动时加载欢迎屏幕 然后用户单击欢迎屏幕上的按钮 然后关闭欢迎屏幕 最后显示主屏幕 static void Main startup method being called Application EnableVisualSt
  • INotifyPropertyChanged 和 propertyName

    我一直不确定它的含义propertyName实施时INotifyPropertyChanged 所以一般来说你实现INotifyPropertyChanged as public class Data INotifyPropertyChan
  • 如何使用placement new重新初始化该字段?

    我的课程包含字段 private OrderUpdate curOrderUpdate 我一遍又一遍地使用它 经常需要重新初始化 for int i 0 i lt entries size i auto entry entries i ne

随机推荐

  • 使 Android 模拟器适用于 1600x1200

    我尝试在模拟器中将 Android 的皮肤布局编辑为 1600x1200 但模拟器无法打开窗口 它适用于较小的分辨率 如 1024x480 等 但不适用于大分辨率 尽管即使使用 1024x480 模拟器窗口的一部分也无法访问且不可见 我的问
  • PHP 编码电子邮件地址

    我需要一条路PHP仅使用对电子邮件地址进行编码a zA Z0 9所以基本上编码时没有任何特殊字符 但随后能够将其解码回原始内容 Example email protected gt ENCODE gt n6bvJjdh7w6QbdVB373
  • NodeJS并行回调设计模式

    我正在尝试找到一个好的模式来执行一堆并行任务 让我定义一些任务来举例说明 任务a b c d e f g执行为a function er ra task a returned ra is result so do b to g 还有一些任务
  • Webpack 反应热加载程序不工作

    下面是我的 webpack config js 代码 var webpack require webpack var path require path module exports context dirname app entry we
  • 右栏按钮项目不显示

    我有以下用于放置 rightbarbuttonitem 的代码 UIButton rightbutton UIButton buttonWithType UIButtonTypeCustom rightbutton setBackgroun
  • 某些 JSON 文件出现 PowerShell FilterScript 错误

    感谢 iRon 本周早些时候提供的帮助question 他对我目前正在进行的一项工作提供了巨大帮助 总之 我们有一个 Azure CICD 管道来部署策略 我们有一个包含 200 多个 JSON 策略文件的文件夹 CICD 流程将它们全部放
  • 使用 to_html 将 CSS 类应用到 Pandas DataFrame

    我在使用 Pandas to html 方法应用 classes 参数来设置 DataFrame 样式时遇到问题 类 str或列表或元组 默认无 应用于生成的 html 表的 CSS 类 从 https pandas pydata org
  • 递归 mod_rewrite 用于搜索引擎友好的 url

    我一直在读以前的解决方案递归 mod rewrite 问题与我想要做的类似 不同之处在于我通过 index php 文件发送所有查询 因此不需要在查询中指定脚本 本质上我想递归地转换搜索引擎友好的 URL 中的任意数量的参数 example
  • 文本框中的永久前缀

    我试图在文本框中输入永久前缀 就我而言 我想要有以下前缀 DOMAIN 这样用户只需在域前缀后输入用户名即可 这不是我必须做或追求的事情 但我的问题更多是出于好奇 我试图想出一些逻辑来做到这一点TextChangedEvent但是 这意味着
  • AngularJS 应用程序的 AssertionUrl

    我的申请流程是这样的 用户输入 Url 然后显示 AngularJS 登录页面 用户单击 使用 SAML 登录 并调用返回 SAML 登录 URL 的 Web API 端点 AngularJS UI 接收 SAML 登录 URL 并将用户重
  • Spark.csv如何确定读取的分区数?

    在 Spark 2 2 0 中 我正在使用以下命令读取一个文件 spark csv read filepath load rdd getNumPartitions 我在一个系统中为 350 MB 文件分配了 77 个分区 在另一个系统中分配
  • TensorFlow Keras 无法处理大于 GPU 内存的 numpy 数组

    我正在尝试处理重量超过 25GB 的样本矩阵 问题是我的 GPU 只有 12GB 内存 我认为 tenorflow 会将小批量的矩阵从 ram 转移到 gRam 如下所述 https stackoverflow com a 53938359
  • 样式未应用于 CSS 中的 H1 元素

    我面临一个奇怪的问题 该样式没有应用于H1元素 Code p h1 color red p p h1 This is a header h1 You can t有一个标题 H1 to H6 作为一个孩子p 这是无效的 HTML 它不起作用
  • SyntaxError:无法在 JEST LWC 中的模块外部使用 import 语句

    我正在尝试使用 Visual Studio Code 作为 IDE 来测试我的第一个 Lightning Web 组件 按照指示 我安装了 Node js npm 和 jest 依赖项 但我收到这个错误 错误图像 当尝试运行下面的代码时 d
  • 是否可以编辑 UIAlertAction 标题字体大小和样式?

    现在iOS8已经弃用了UIActionsheet and UIAlertviewiOS7 上的自定义不再生效 到目前为止 我知道的唯一定制是色调颜色 我需要的是改变标题的字体大小和样式 但我还没有找到任何方法可以用新的UIAlertActi
  • SQL AND 运算符无法正常工作

    我有以下两张表 地块表 Blockid ParcelNo storPri 52000105 3 State 52000105 4 Private 52000105 5 State 行动表 Blockid ParcelNo ActionTak
  • Pandas 中的可变位移

    数据框中有两列 A 和 B A B 0 1 6 1 2 7 2 1 8 3 2 9 4 1 10 我想创建一个列 C C 必须将 B 的值移动 A 的值 A B C 0 1 6 NaN 1 2 7 NaN 2 1 8 7 3 2 9 7 4
  • ImageMagick 比较:忽略 PSNR 结果中的白色匹配

    我在用着compare区分两个相似的colorPNG 文件 他们得到一个PSNR值 27 图像包含许多白色区域 两个图像之间始终匹配 如果我错了 请纠正我 但这些白色区域正在增加 PSNR 值 使图像作为平均值更加相似 因此我不想考虑白色像
  • 如何以编程方式在所需文件夹中创建 SQL Server 2008 数据库完整备份

    如何使用 Microsoft Visual Studio 2010 c 以编程方式在所需文件夹中创建 SQL Server 2008 数据库完整备份 只需执行 SQL Servercommand BACKUP DATABASE databa
  • C11 中的内存顺序消耗使用情况

    我读到了关于带有依赖性关系和依赖顺序先于在其定义中使用 15 1 2 4 p16 评价A在评估之前是依存顺序的B if A对原子对象执行释放操作M 并且 在另一个 线 B执行消费操作M并读取写入的值 由释放序列中的任何副作用引起A or 一