首先让我提一下,静态全局变量与全局变量相同,只是您将变量限制在文件的范围内。 IE。您不能通过 extern 关键字在其他文件中使用此全局变量。
因此,您可以将问题简化为全局变量与易变变量。
现在进入 volatile:
像const,volatile 是一个类型修饰符。
创建volatile 关键字是为了防止编译器优化可能导致代码不正确,特别是在存在异步事件时。
声明为volatile 的对象不能用于某些优化。
系统总是在使用 volatile 对象时读取它的当前真实值,即使之前的指令要求来自同一对象的值也是如此。此外,对象的值在赋值时立即写入。这意味着没有将 volatile 变量缓存到 CPU 寄存器中。
Dr. Jobb's has a great article on volatile.
这里是乔布博士文章中的一个例子:
class Gadget
{
public:
void Wait()
{
while (!flag_)
{
Sleep(1000); // sleeps for 1000 milliseconds
}
}
void Wakeup()
{
flag_ = true;
}
...
private:
bool flag_;
};
如果编译器发现Sleep() 是一个外部调用,它将假定Sleep() 不可能更改变量flag_ 的值。因此编译器可以将flag_ 的值存储在寄存器中。在那种情况下,它永远不会改变。但是如果另一个线程调用唤醒,第一个线程仍然在读取 CPU 的寄存器。 Wait() 永远不会醒来。
那么为什么不直接将变量缓存到寄存器中并完全避免问题呢?
事实证明,这种优化确实可以总体上为您节省大量时间。因此,C/C++ 允许您通过 volatile 关键字显式禁用它。
flag_ 是成员变量,而不是全局变量(也不是静态全局变量)这一事实无关紧要。即使您正在处理全局变量(和静态全局变量),示例之后的解释也给出了正确的推理。
一个常见的误解是声明变量volatile 足以确保线程安全。对变量的操作仍然不是原子的,即使它们没有“缓存”在寄存器中
带有指针的易失性:
带有指针的易失性,就像带有指针的 const 一样。
volatile int * 类型的变量意味着指针指向的变量是 volatile。
int * volatile 类型的变量意味着指针本身是易失的。