c - 从两个不同索引处的 2 个不同线程写入 float 组是否安全?

标签 c multithreading

float myfloats[2];

// thread A:
myFloats[0] = 1.0;

// thread B:
myFloats[1] = 1.0;

假设线程 A 将始终访问索引 0,线程 B 始终访问索引 1。这是否安全或数组是否会损坏?

最佳答案

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


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

5.1.2.4 Multi-threaded executions and data races

4. Two expression evaluations conflict if one of them modifies a memory location and the other one reads or modifies the same memory location.

25. The execution of a program contains a data race if it contains two conflicting actions in different threads, at least one of which is not atomic, and neither happens before the other. Any such data race results in undefined behavior.

27. NOTE 13 Compiler transformations that introduce assignments to a potentially shared memory location that would not be modified by the abstract machine are generally precluded by this standard, since such an assignment might overwrite another assignment by a different thread in cases in which an abstract machine execution would not have encountered a data race. This includes implementations of data member assignment that overwrite adjacent members in separate memory locations. We also generally preclude reordering of atomic loads in cases in which the atomics in question may alias, since this may violate the "visible sequence" rules.

28. NOTE 14 Transformations that introduce a speculative read of a potentially shared memory location may not preserve the semantics of the program as defined in this standard, since they potentially introduce a data race. However, they are typically valid in the context of an optimizing compiler that targets a specific machine with well-defined semantics for data races. They would be invalid for a hypothetical machine that is not tolerant of races or provides hardware race detection.

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

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


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

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

真正的共享如果相关线程都访问缓存行的同一部分,因为这种无效被证明是为了防止通信线程使用陈旧数据。

另一方面,如果线程都访问同一缓存行的不同部分,则会发生虚假共享。在这种情况下,无效是不必要的,但由于访问彼此接近,硬件还是执行了无效,对所有访问进行了惩罚。

关于c - 从两个不同索引处的 2 个不同线程写入 float 组是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20458673/

相关文章:

Java TCP 多用户聊天服务器客户端与服务器的连接存在问题

Linux:多核 CPU 中的进程和线程

c - **矩阵的工作方式与矩阵[行][列]有何不同?

C 连接两个函数

c - 如何将 char* 传递给函数?

mysql - Ruby Shoes 和 MySQL : GUI freezes, 我应该使用线程吗?

在 Ubuntu 11.10 下从源代码编译ettercap 0.7.4.1(链接器错误)

c - 在写入文件和标准输出之间切换

c - Win32 在当前控制台执行子进程并退出而不返回父进程

java - 使用并发来提高性能