是从两个不同的索引写入一个浮点数组安全吗?

 Benson 发布于 2023-02-12 10:30

C11 n1570标准草案似乎断言这是安全的,但我断言这是不明智的


我的论据是基于数组的元素在内存中不能重叠的事实,以及C11标准草案的以下条款。

5.1.2.4 多线程执行和数据竞争

4. 如果两个表达式求值中的一个修改内存位置,而另一个表达式读取或修改相同的内存位置,则这两个表达式求值冲突

25.如果一个程序的执行在不同的线程中包含两个冲突的动作,则其中至少一个不是原子的,并且两个动作都不比另一个更早发生,则该程序的执行将引起数据争用。任何此类数据争用都会导致未定义的行为。

27.注13:通常,此标准排除了将分配引入可能不会由抽象机修改的潜在共享内存位置的编译器转换,因为在抽象机的情况下,这种分配可能会通过不同的线程覆盖另一个赋值执行将不会遇到数据争用。这包括数据成员分配的实现,这些实现将覆盖单独的内存位置中的相邻成员。通常,在所讨论的原子可能会混叠的情况下,我们通常也避免对原子负载进行重新排序,因为这可能违反“可见序列”规则。

28.注14:引入潜在共享内存位置的推测读取的转换可能不会保留此标准中定义的程序的语义,因为它们潜在地引入了数据竞争。但是,它们通常在优化编译器的上下文中有效,该编译器针对具有明确定义的语义的特定机器针对数据竞争进行了优化。对于不容忍竞争或无法提供硬件竞争检测的假设机器,它们将无效。

我们在这里了解到,两个线程在同一内存位置上执行冲突操作是UB,但是编译器“通常被阻止”将分配引入抽象机器不会执行的“潜在共享”内存位置。

您断言线程只访问(读取和写入)位于其自己特定索引处的元素。由于毫无疑问,他们不会访问相同的内存位置,因此在我看来,只要您满足所有其他约束(例如float变量的正确对齐),您的操作就很安全。


但是,我质疑按照您的建议做事的智慧。由于这两个内存位置是连续的,因此您可能会遇到严重的错误共享问题。这是因为CPU通常以大约32或64个连续字节的“行”形式缓存内存,并使用MESI协议传达缓存状态。

如果在一个内核上运行的线程在此高速缓存行中的任何位置执行写操作,则该高速缓存行的所有副本以及在其他内核中找到的包含在其中的所有内容都会失效,通常会导致那些其他内核上的线程需要从主内存中重新读取其更新后的副本。这比从缓存访问要慢几倍。

如果所有相关线程都在访问高速缓存行的同一部分,则会发生真正的共享,因为这样做是有道理的,以防止通信线程使用陈旧数据。

另一方面,如果线程都访问同一高速缓存行的不同部分,则会发生错误共享。在这种情况下,无效是没有必要的,但是由于相互之间的访问距离很近,因此硬件无论如何都将其无效,这将对所有这些进行惩罚。

撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有