其他线程会在合理的时间内看到对“volatile”字大小变量的写入吗



当问到一个更具体的问题时,我发现这是人们不太确定的核心问题。

可以做出以下假设:

  • CPU确实使用了类似MESI(F)的缓存一致性协议(例如:x86/x86_64和ARMv7mp)
  • 假设变量的大小由处理器以原子方式写入/读取(对齐和本地字大小)
  • 变量声明为volatile

问题是:

  • 如果我在一个线程中写入变量,其他线程会看到变化吗
  • 其他线程将看到变化的时间范围的数量级是多少
  • 您知道缓存一致性不足以确保跨CPU/跨核心可见性的体系结构吗

问题不是:

  • 使用这样的变量安全吗
  • 关于重新排序问题
  • 关于C++11原子

这可能被认为是C/C++中的重复,volatile变量是否保证最终在线程之间具有一致的语义?以及其他类似的问题,但我认为这些问题都没有关于目标架构的明确要求,这导致了对不同假设的混淆。

您知道缓存一致性不足以确保跨cpu/跨核心可见性的体系结构吗?

我不知道任何一个具有多核的处理器存在缓存一致性问题。可能有人在多处理器板中使用了错误类型的处理器,例如禁用了英特尔所称的外部QPI的英特尔处理器,但这会导致各种问题。

关于英特尔QPI以及哪些处理器启用或禁用QPI的Wiki文章:

http://en.wikipedia.org/wiki/Intel_QuickPath_Interconnect

如果我在一个线程中写入变量,其他线程会看到变化吗?

无法保证。如果你认为有,告诉我你在哪里找到的。

其他线程将看到变化的时间范围的数量级是多少?

永远都不可能。无法保证。

您知道缓存一致性不足以确保跨cpu/跨核心可见性的体系结构吗?

这是一个不连贯的问题,因为您谈论的是C++代码中必须编译成汇编代码的操作。即使您有适用于汇编代码的硬件保证,也不能保证这些保证"传递"到C++代码。

但就这个问题可以得到的回答而言,答案是肯定的。实际平台中存在已发布的写入、读取预取和其他类型的缓存(例如编译器对寄存器的处理)。

我会说不,没有保证。存在使用多个独立计算机的实现,其中共享数据必须通过计算机之间的(通常非常快的)连接进行传输。在这种情况下,你会尝试只在需要的时候传输数据。例如,这可能是由互斥体和标准原子函数触发的,但希望不是通过存储到任意本地内存中,也可能不是通过存储在易失性内存中。

我可能错了,但你必须证明我错了。

假设现在的x86/64:

如果我在一个线程中写入变量,其他线程会看到变化吗?

是的。假设您使用的是一个现代的、不太旧的/有缺陷的编译器。

其他线程将看到变化的时间范围的数量级是多少?

这真的取决于你如何衡量。基本上,这将是相同NUMA节点上的内存延迟时间=200个周期。在另一个节点上,在一个2节点框上,大约加倍。对于更大的盒子可能会有所不同。如果您的写入相对于时间测量点被重新排序,则可以获得+/-50个周期。

几年前,我测量了这一点,在3GHz的盒子上得到了60-70ns,在另一个节点上得到了两倍。

您知道缓存一致性不足以确保跨cpu/跨核心可见性的体系结构吗?

我认为缓存一致性的意义在于可见性。话虽如此,我不确定Sun risk机器是否具有与x86相同的缓存一致性和宽松的内存模型,所以我会非常仔细地对它们进行测试。具体来说,您可能需要添加内存释放屏障来强制刷新内存写入。

根据您所描述的假设,不能保证在一个线程中写入volatile变量会在另一个线程"看到"。

鉴于此,您的第二个问题(关于时间框架)不适用。

对于(多处理器)PowerPC体系结构,缓存一致性不足以确保volatile变量的跨核心可见性。需要执行一些明确的指令,以确保状态被刷新(并使其在多个处理器及其缓存中可见)。

在实践中,在需要执行此类指令的体系结构上,数据同步原语(互斥、信号量、关键部分等)的实现确实使用了这些指令。

更广泛地说,C++中的volatile关键字与多线程无关,更不用说与跨缓存一致性有关了。在给定的执行线程中,volatile转化为对变量的获取和写入等事情的需要,而编译器没有消除或重新排序(这会影响优化)。它不会转化为任何关于在执行线程之间完成获取或写入的顺序或同步的要求,而这些要求对于缓存一致性是必要的。

从概念上讲,编译器可能被实现来提供这样的保证。我还没有看到任何关于这样做的信息——这并不奇怪,因为提供这样的保证会通过强制线程之间的同步来严重影响多线程代码的性能——即使程序员在代码中没有使用同步(互斥等)。

类似地,主机平台名义上也可以用volatile变量提供这样的保证——即使执行的指令并不特别需要它们。同样,这会降低多线程程序(包括现代操作系统)在这些平台上的性能。它还将通过迫使处理器相互等待来影响(或否定)有助于现代处理器性能的各种功能的好处,例如流水线。

作为一名C++开发人员(与编写利用特定编译器或主机平台提供的特定功能的代码的人不同),如果您希望在一个线程中编写的变量能够被另一个线程连贯地读取,那么就不要使用volatile了。当线程需要同时访问同一个变量时,使用所提供的技术(如互斥)在线程之间执行同步。并遵循使用这些技术的常规指导原则(例如,谨慎使用互斥锁并尽量减少它们的保存时间,在线程中尽可能多地执行操作,而不访问线程之间共享的变量)。

相关内容

  • 没有找到相关文章

最新更新