代码之家  ›  专栏  ›  技术社区  ›  Jack Lloyd

在C/C++中,易失性变量保证线程最终具有一致的语义吗?

  •  10
  • Jack Lloyd  · 技术社区  · 14 年前

    是否有任何通常遵循的标准(ISOC或C++),或 任何一个posix/sus规范,一个变量(可能 标记为volatile),不受正在访问的互斥锁保护 通过多个线程将最终成为一致的,如果 分配给?

    为了提供一个特定的示例,考虑两个线程共享一个 变量V,初始值为零。

    线程1: V=1

    线程2: (V=0) 屈服();

    线程2是否保证最终终止?还是可以 可以想象,永远旋转,因为缓存的一致性永远不会起作用。 在线程2的缓存中并使分配可见?

    我知道C和C++标准(在C++ 0x之前)不说话。 关于线程或并发。但我很好奇c++ 0x 内存模型,或者pthreads,或者其他任何东西,都保证了这一点。 (显然,这确实适用于32位x86上的Windows;我想知道这是否是一个可以普遍依赖的东西,或者它只是在那里工作)。

    6 回复  |  直到 9 年前
        1
  •  12
  •   Community CDub    7 年前

    这将取决于你的架构。虽然要求显式缓存刷新或内存同步以确保内存写入对其他线程可见是不寻常的,但没有什么能阻止它,而且我确实遇到过必须执行显式指令以确保状态刷新的平台(包括我当前正在为之开发的基于PowerPC的设备)。

    请注意,线程同步原语(如mutex)将根据需要执行必要的工作,但如果您只想确保状态可见而不考虑一致性,则通常不需要线程同步原语-只需同步/刷新指令即可。

    编辑:对任何仍对 volatile 关键字- 不稳定的 保证编译器不会生成显式缓存寄存器中数据的代码,但这是 不是 与处理透明缓存/重新排序读写的硬件一样。例如阅读 this this this Dobbs博士的文章,或者答案 this 所以,你可以提问,或者选择你最喜欢的编译器,它的目标是一个弱一致的内存结构,比如cell,编写一些测试代码,并将编译器生成的代码与你需要的代码进行比较,以确保写操作对其他进程是可见的。

        2
  •  5
  •   AProgrammer    14 年前

    如果我已经正确理解了相关的部分,c++ 0x就不能保证它是独立变量,甚至是易失性变量(它不是为使用而设计的),而是会引入原子类型来保证它(见头)。 <atomic> )

        3
  •  3
  •   R Samuel Klatchko    14 年前

    首先,如果它没有标记为volatile,编译器很可能只加载一次。因此,无论内存最终是否改变,都不能保证编译程序会设置它。

    因为您明确地说“没有互斥体”,所以pthreads不适用。

    除此之外,由于C++没有内存模型,它依赖于硬件体系结构。

        4
  •  3
  •   curiousguy    13 年前

    这是一场潜在的数据竞赛。

    对于posix线程,这是ub。与C++一样,我相信。

    实际上,我无法想象它会怎么失败。

        5
  •  2
  •   Stack Overflow is garbage    9 年前

    线程2是否保证最终终止?或者,它是否可以永远旋转,因为缓存一致性永远不会启动,并且使分配在线程2的缓存中可见?

    如果变量不是可变的,您就没有任何保证。在C++0X之前,该标准对线程没有任何意义,而且由于变量不是易失性的,所以读/写被认为是不可观察的副作用,所以编译器可以作弊。在C++0X之后,这是一个争用条件,它被明确地声明为未定义的行为。

    如果变量是可变的,则可以得到读/写的保证 这样,编译器就不会根据其他易失性内存访问进行重新排序。(然而,这本身并不能保证CPU不会重新排序这些内存访问——只是编译器不会这样做)

    但您不能保证它不会相对于其他非易失性访问进行重新排序,因此您可能无法获得预期的行为。尤其是,如果编译器认为这样做是安全的(也是有益的),那么在while循环之后,您试图“保护”的一些指令可能会被移到循环前面。但是在执行这个分析时,它只关注当前线程,而不关注其他线程中发生的事情。

    因此,不,一般来说,即使在 volatile . 可能,也可能 经常 会,但并非总是如此(这取决于循环之后会发生什么)。这取决于编译器愿意在多大程度上进行优化。但它是 允许 去足够远的地方破坏代码。所以不要依赖它。如果您想围绕这样的东西进行同步,请使用内存屏障。这就是他们的目的。(如果你这样做,你甚至不需要 不稳定的 再多)

        6
  •  0
  •   Jens Gustedt    14 年前

    我认为它最终会在任何平台上工作,但不知道你可能看到的延迟。

    但是,老实说,在投票等待事件的时候进行投票是非常糟糕的方式。即使你做了 yield 您的进程将被一次又一次地重新安排,而不做任何事情。

    既然您已经知道如何将一个变量放置在两个变量都可以访问的地方,那么为什么不使用正确的工具来执行一个不会耗尽资源的等待呢?一对 pthread_mutex_t pthread_cond_t 完全可以做到。