11

在什么情况下让两个不同的线程同时写入 x86 上同一数组的相邻元素是不安全的?我知道在某些具有疯狂内存模型的类似 DS9K 的架构上,这可能会导致字撕裂,但在 x86 上,单个字节是可寻址的。例如,在 D 编程语言real中是 x86 上的 80 位浮点类型。执行以下操作是否安全:

real[] nums = new real[4];  // Assume new returns a 16-byte aligned block.
foreach(i; 0..4) {
    // Create a new thread and have it do stuff and 
    // write results to index i of nums.
}

注意:我知道,即使这是安全的,它有时也会导致缓存的错误共享问题,从而导致性能下降。但是,对于我想到的用例,写入将很少见,以至于这在实践中并不重要。

编辑:不要担心读回写入的值。假设是在读取任何值之前会有同步。我只关心这样的安全性。

4

3 回答 3

11

x86 具有一致的缓存。最后一个写入高速缓存行的处理器获取整个内容并写入高速缓存。这确保了写入相应值的单字节和 4 字节值被原子更新。

这与“它的安全”不同。如果每个处理器都只写入该处理器“拥有”的字节/DWORDS,那么更新将是正确的。实际上,您希望一个处理器读取其他处理器写入的值,这需要同步。

它也不同于“高效”。如果多个处理器可以分别写入缓存线中的不同位置,那么缓存线可以在 CPU 之间进行乒乓球运动,这比缓存线进入单个 CPU 并停留在那里要昂贵得多。通常的规则是将特定于处理器的数据放在它自己的高速缓存行中。当然,如果您只想写入一个单词,一次,并且与缓存行移动相比,工作量很大,那么您的性能将是可以接受的。

于 2009-10-22T14:06:28.490 回答
1

我可能会遗漏一些东西,但我没有预见到任何问题。x86 架构只写入它需要的内容,它不会在指定值之外进行任何写入。Cache-snooping 处理缓存问题。

于 2009-10-22T14:00:58.690 回答
1

您在询问 x86 细节,但您的示例使用的是某种高级语言。您关于 D 的具体问题只能由编写您正在使用的编译器的人来回答,或者也许是 D 语言规范。例如,Java 要求数组元素访问不得导致撕裂。

关于 x86,操作的原子性在英特尔软件开发人员手册第 3A 卷的第 8.1 节中指定。根据它,原子存储操作包括:在所有 x86 CPU 上存储一个字节、存储字对齐字和双字对齐 dword。它还指定在 P6 和更高版本的 CPU 上,对高速缓存行内的高速缓存内存的未对齐 16、32 和 64 位访问是原子的。

于 2009-10-30T03:08:59.177 回答