【问题标题】:Word Tearing on x86x86 上的字撕裂
【发布时间】:2009-10-22 13:51:50
【问题描述】:

在什么情况下让两个不同的线程同时写入 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.
}

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

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

【问题讨论】:

  • 我假设您正在查看相邻地址的脏写?

标签: multithreading thread-safety parallel-processing d race-condition


【解决方案1】:

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

这与“它的安全”不同。如果每个处理器仅按设计写入该处理器“拥有”的字节/DWORDS,则更新将是正确的。在实践中,您希望一个处理器读取其他处理器写入的值,这需要 同步。

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

【讨论】:

  • 关于阅读的观点:这个想法是使用平行地图之类的东西并行填充一个巨大的数组。映射函数将花费大部分时间,因此写入所花费的时间可以忽略不计,并且无论如何缓存行只会在工作单元的边界附近共享。在从该数组读回任何值之前,将使用某种类型的同步。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    关于 x86,操作的原子性在 Intel's Software Developer's Manual Volume 3A 的第 8.1 节中指定。根据它,原子存储操作包括:在所有 x86 CPU 上存储一个字节、存储字对齐的字和双字对齐的 dword。它还指定在 P6 和更高版本的 CPU 上,对高速缓存行中的高速缓存内存的未对齐 16、32 和 64 位访问是原子的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-04
      • 2012-06-15
      • 2011-04-09
      • 1970-01-01
      • 1970-01-01
      • 2012-12-09
      • 1970-01-01
      相关资源
      最近更新 更多