gpt4 book ai didi

c++ - 为什么 volatile 在多线程 C 或 C++ 编程中没有用处?

转载 作者:行者123 更新时间:2023-11-30 16:22:26 26 4
gpt4 key购买 nike

this answer中所示我最近发帖,我似乎对多线程编程上下文中 volatile 的实用性(或缺乏实用性)感到困惑。

我的理解是这样的:任何时候一个变量可能在访问它的一段代码的控制流之外被更改,该变量应该被声明为 volatile 。信号处理程序、I/O 寄存器以及被另一个线程修改的变量都构成这种情况。

因此,如果您有一个全局 int foo,并且 foo 由一个线程读取并由另一个线程原子设置(可能使用适当的机器指令),则读取线程看到这种情况的方式与看到由信号处理程序调整的变量或由外部硬件条件修改的变量的方式相同,因此 foo 应该声明为 volatile (或者,对于多线程情况,通过内存隔离负载访问,这可能是一个更好的解决方案)。

我哪里错了?

最佳答案

volatile 的问题在多线程上下文中,它没有提供我们需要的全部保证。它确实有一些我们需要的属性,但不是全部,所以我们不能依赖 volatile 单独

但是,我们必须用于其余属性的原语也提供了 volatile 的原语。确实如此,所以实际上没有必要。

为了对共享数据进行线程安全访问,我们需要保证:

  • 读/写实际上发生了(编译器不会只是将值存储在寄存器中,而是推迟更新主内存直到很久以后)
  • 不会发生重新排序。假设我们使用 volatile变量作为标志来指示某些数据是否准备好读取。在我们的代码中,我们只需在准备数据后设置标志,因此一切看起来都很好。但是,如果指令被重新排序,因此标志首先被设置怎么办?

volatile确实保证了第一点。它还保证不同的 volatile 读/写之间不会发生重新排序。全部volatile内存访问将按照指定的顺序发生。这就是我们所需要的 volatile用于:操作 I/O 寄存器或内存映射硬件,但它对我们在多线程代码中没有帮助,其中 volatile对象通常仅用于同步对非 volatile 数据的访问。这些访问仍然可以相对于 volatile 重新排序。的。

防止重新排序的解决方案是使用内存屏障,它向编译器和 CPU 表明此时不能对内存访问进行重新排序。在我们的 volatile 变量访问周围放置这样的屏障,可以确保即使是非 volatile 访问也不会在 volatile 变量之间重新排序,从而使我们能够编写线程安全的代码。

但是,内存屏障确保在到达屏障时执行所有挂起的读/写操作,因此它有效地为我们提供了本身所需的一切,使得 volatile不必要。我们可以删除 volatile完全限定符。

自 C++11 起,原子变量 ( std::atomic<T> ) 为我们提供了所有相关保证。

关于c++ - 为什么 volatile 在多线程 C 或 C++ 编程中没有用处?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54437515/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com