代码之家  ›  专栏  ›  技术社区  ›  Eran

设置一个位是否与同一个字上其他位的并发集冲突?

  •  4
  • Eran  · 技术社区  · 14 年前
    1. 假设我有一个位图,几个线程(在几个CPU上运行)正在上面设置位。不使用同步,也不使用原子操作。此外,不进行重置。据我所知,当两个线程试图在同一个单词上设置两个位时,最终只有一个操作会坚持。原因是要设置一个位,整个单词应该读写,所以当两个读操作同时完成时,写回一个操作将覆盖另一个操作。对吗?

    2. 如果上面是真的,那么字节操作也是这样吗?也就是说,如果一个字是2个字节,并且每个线程都试图将一个不同的字节设置为1,那么它们在并发执行时是否也会相互覆盖,或者某些系统是否支持将结果只写回一个字的一部分?

    问这个问题的原因是想弄清楚为了省略位/字节/字映射操作中的同步,我必须放弃多少空间。

    3 回复  |  直到 14 年前
        1
  •  5
  •   Roddy    14 年前

    简而言之,它非常依赖于CPU和编译器。

    假设您有一个包含零的32位值,线程A想要设置位0,线程B想要设置位1。

    正如您所描述的,这些是读-修改-写操作,同步问题是“如果它们发生冲突会发生什么”。

    您需要避免的情况是:

    A: Reads (gets 0)
    B: Reads (also gets zero)
    A: Logical-OR bit 0, result = 1
    A: Writes 1
    B: Logical-OR bit 1, result = 2
    B: Writes 2 - oops, should have been 3
    

    …当正确的结果是…

    A: Reads (gets 0)
    A: Logical-OR bit 0, result = 1
    A: Writes 1
    B: Reads (gets 1)
    B: Logical-OR bit 1, result = 2
    B: Writes 3 - correct
    

    在某些处理器上,读-修改-写将是三个独立的指令,因此需要同步。在其他方面,它将是一个单一的原子指令。在多个核心/CPU系统上,它将是一条单指令,但其他核心/CPU可能能够访问,因此再次需要同步。

    用字节来做可以是相同的。在某些处理器内存体系结构中,只能写入32位内存值,因此字节更新需要像以前一样进行读-修改-写操作。

    x86体系结构(尤其是Windows)的更新

    Windows提供了一组32位值的原子“互锁”操作,包括 Logical OR . 在避免关键部分时,这些可能对您有很大帮助。但要小心,因为正如陈瑞蒙指出的, they don't solve everything . 一直读那篇文章直到你明白!

        2
  •  2
  •   Ned Batchelder    14 年前

    这些细节将依赖于系统,并且可能依赖于编译器。我想,在你摆脱恐惧的影响之前,你可能需要一直到32位整数。

        3
  •  1
  •   Giuliano Vilela    14 年前
    1. 我相信这是真的,因为你说的原因。

    2. 在我看来,如果位图存储为 char[] 如果您的体系结构是字节可寻址的(可以在内存中读取和写入单个字节,而不必读取整个单词),那么编译器可以生成原子操作。尽管如此,它完全是实现定义的,所以您不能依赖它。