volatile关键字的作用是什么?在c++中它能解决什么问题?
就我而言,我从来没有明知肚明地需要它。
volatile关键字的作用是什么?在c++中它能解决什么问题?
就我而言,我从来没有明知肚明地需要它。
当前回答
如果你正在从内存中的某个点(比如说,一个完全独立的进程/设备/任何东西)读取数据,则需要使用Volatile。
我曾经在纯c的多处理器系统中使用双端口ram。我们使用硬件管理的16位值作为信号量,以知道另一个家伙什么时候完成。基本上我们是这样做的:
void waitForSemaphore()
{
volatile uint16_t* semPtr = WELL_KNOWN_SEM_ADDR;/*well known address to my semaphore*/
while ((*semPtr) != IS_OK_FOR_ME_TO_PROCEED);
}
没有volatile,优化器认为循环是无用的(这家伙从不设置值!他疯了,删掉那代码吧!),我的代码会在没有获得信号量的情况下继续运行,从而在以后造成问题。
其他回答
在开发嵌入式系统或设备驱动程序时,需要使用Volatile,因为在这些驱动程序中需要读写内存映射的硬件设备。特定设备寄存器的内容随时都可能改变,所以你需要volatile关键字来确保这样的访问不会被编译器优化。
除了按预期使用它,volatile还用于(模板)元编程。它可以用来防止意外重载,因为volatile属性(如const)参与了重载解析。
template <typename T>
class Foo {
std::enable_if_t<sizeof(T)==4, void> f(T& t)
{ std::cout << 1 << t; }
void f(T volatile& t)
{ std::cout << 2 << const_cast<T&>(t); }
void bar() { T t; f(t); }
};
这是合法的;这两个重载都可能是可调用的,并且执行几乎相同的操作。在volatile重载中的强制转换是合法的,因为我们知道bar无论如何都不会通过一个非volatile T。不过,volatile版本严格来说更糟糕,所以如果非volatile f可用,则永远不要在重载分辨率中选择。
注意,代码实际上从不依赖于volatile内存访问。
在实现无锁数据结构时必须使用volatile。否则,编译器可以自由地优化对变量的访问,这将改变语义。
换句话说,volatile告诉编译器对这个变量的访问必须对应于物理内存的读/写操作。
例如,这是Win32 API中InterlockedIncrement的声明方式:
LONG __cdecl InterlockedIncrement(
__inout LONG volatile *Addend
);
一些处理器具有超过64位精度的浮点寄存器(例如。32位x86没有SSE,见Peter的评论)。这样,如果您对双精度数运行多次操作,实际上会得到比将每个中间结果截断为64位更高精度的答案。
这通常很好,但这意味着根据编译器如何分配寄存器和进行优化,对于完全相同的输入,完全相同的操作将得到不同的结果。如果您需要一致性,那么您可以使用volatile关键字强制每个操作返回内存。
它对于一些没有代数意义但减少浮点误差的算法也很有用,比如Kahan求和。代数上它是一个nop,所以它经常会被错误地优化除非一些中间变量是不稳定的。
如果你正在从内存中的某个点(比如说,一个完全独立的进程/设备/任何东西)读取数据,则需要使用Volatile。
我曾经在纯c的多处理器系统中使用双端口ram。我们使用硬件管理的16位值作为信号量,以知道另一个家伙什么时候完成。基本上我们是这样做的:
void waitForSemaphore()
{
volatile uint16_t* semPtr = WELL_KNOWN_SEM_ADDR;/*well known address to my semaphore*/
while ((*semPtr) != IS_OK_FOR_ME_TO_PROCEED);
}
没有volatile,优化器认为循环是无用的(这家伙从不设置值!他疯了,删掉那代码吧!),我的代码会在没有获得信号量的情况下继续运行,从而在以后造成问题。