c++ - 编译器在处理 volatile 内存位置时必须遵循哪些规则?

标签 c++ memory compiler-construction rules volatile

我知道当从多个线程或进程写入的内存位置读取时,volatile 关键字应该用于该位置,如下面的某些情况,但我想了解更多有关哪些限制的信息它真的对编译器有用吗?基本上编译器在处理这种情况时必须遵循什么规则,是否存在任何异常(exception)情况,尽管同时访问内存位置,但程序员可以忽略 volatile 关键字。

volatile SomeType * ptr = someAddress;
void someFunc(volatile const SomeType & input){
 //function body
}

最佳答案

你知道的都是假的。 Volatile 用于同步线程之间的内存访问,应用任何类型的内存栅栏或任何类型的东西。 volatile 内存上的操作不是原子的,也不保证它们按任何特定顺序进行。 volatile 是整个语言中最容易被误解的工具之一。 "Volatile is almost useless for multi-threadded programming. "

volatile 用于连接内存映射硬件、信号处理程序和 setjmp 机器代码指令。

它也可以像使用 const 一样使用,这就是 Alexandrescu 在 this article 中使用它的方式。 .但不要搞错。 volatile 不会让你的代码神奇地线程安全。以这种特定方式使用,它只是一个工具,可以帮助编译器告诉你你可能在哪里搞砸了。修复错误仍然取决于您,而 volatile 在修复这些错误中没有任何作用

编辑:我将尝试详细说明我刚才所说的内容。

假设你有一个类,它有一个指向不能改变的东西的指针。您可能会自然地将指针设为 const:

class MyGizmo
{ 
public:
  const Foo* foo_;
};

const 在这里真正为您做什么?它对内存没有任何作用。它不像旧软盘上的写保护标签。内存本身仍然是可写的。您只是无法通过 foo_ 指针对其进行写入。所以 const 实际上只是为编译器提供另一种方式来让你知道什么时候可能会搞砸。如果你要写这段代码:

gizmo.foo_->bar_ = 42;

...编译器不允许这样做,因为它被标记为 const。显然你可以通过使用 const_cast 来摆脱 const-ness 来解决这个问题,但如果你需要确信这是一个坏主意,那么对你没有任何帮助. :)

Alexandrescu 对 volatile 的使用完全相同。它不会做任何事情来使内存以某种方式“线程安全”以任何方式。它的作用是它为编译器提供了另一种方式,让您知道您何时可能搞砸了。你将你真正“线程安全”的东西(通过使用实际的同步对象,如互斥锁或信号量)标记为volatile。然后编译器不会让你在非volatile 上下文中使用它们。它会引发编译器错误,然后您必须考虑并修复。你可以再次通过使用 const_cast 抛弃 volatile-ness 来绕过它,但这与抛弃 const-ness 一样邪恶。

我对您的建议是完全放弃将 volatile 作为编写多线程应用程序的工具(编辑:),直到您真正知道自己在做什么以及为什么。它有一些好处,但不是大多数人想的那样,如果你使用不当,你可能会编写出危险的不安全应用程序。

关于c++ - 编译器在处理 volatile 内存位置时必须遵循哪些规则?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4136900/

相关文章:

c++ - 使用Eigen::FFT执行FFT时的频率

c++ - cygwin 异常堆栈转储文件错误?

compiler-construction - LLVM中的部分应用

javascript - 关于大型 JS 变量并将它们保留为 'in memory' 的经验法则?

Python - Pygame 突然变慢

optimization - 编译器优化会引入错误吗?

c++ - 如何在 Xcode 4.5 中启用 MacPorts 安装的 gcc4.7(和 libstdc++)?

C++ 预处理器指令

C++:结构访问速度比基本变量慢?

java - 如果 equals 方法返回 true,如何在内存中分配相同的空间?