|
1
231
我过去用C语言在多处理器系统中使用双端口ram。我们使用硬件管理的16位值作为信号量,以了解对方何时完成。基本上,我们做到了这一点:
没有
|
|
|
2
73
|
|
3
65
一些处理器具有精度超过64位的浮点寄存器(例如,没有SSE的32位x86,请参阅Peter的评论)。这样,如果你对双精度数字运行几个操作,你实际上会得到比将每个中间结果截断为64位更高的精度答案。 这通常很好,但这意味着,根据编译器如何分配寄存器和进行优化,对完全相同的输入执行完全相同的操作会得到不同的结果。如果你需要一致性,那么你可以使用volatile关键字强制每个操作返回内存。 它也适用于一些没有代数意义但减少浮点误差的算法,如Kahan求和。从代数上讲,这是一个nop,所以除非一些中间变量是易变的,否则它经常会被错误地优化。 |
|
|
4
41
从a “波动如承诺” Dan Saks的文章:
以下是他关于
|
|
|
5
23
在实现无锁数据结构时,必须使用volatile。否则,编译器可以自由地优化对变量的访问,这将改变语义。 换句话说,volatile告诉编译器对这个变量的访问必须对应于物理内存读/写操作。 例如,以下是在Win32 API中声明InterlockedIncrement的方式:
|
|
|
6
10
我在20世纪90年代初开发的一个大型应用程序包含使用setjmp和longjmp的基于C的异常处理。volatile关键字对于需要在充当“catch”子句的代码块中保留值的变量是必要的,以免这些变量存储在寄存器中并被longjmp擦除。 |
|
7
10
在标准C中,使用的地方之一
这意味着在标准C中,你可以写:
除此之外,别无其他。
POSIX在信号处理程序中可以做什么方面要宽松得多,但仍然存在局限性(其中一个局限性是标准I/O库
|
|
|
8
8
为嵌入式开发,我有一个循环,用于检查可以在中断处理程序中更改的变量。如果没有“volatile”,循环就变成了noop——据编译器所知,变量永远不会改变,因此它优化了检查。 同样的事情也适用于在更传统的环境中可能在不同线程中更改的变量,但我们经常在那里进行同步调用,因此编译器在优化方面并不那么自由。 |
|
|
9
7
我在调试构建中使用过它,当编译器坚持优化一个变量时,我希望在我逐步执行代码时能够看到它。 |
|
|
10
6
除了按预期使用它之外,volatile还用于(模板)元编程。它可用于防止意外过载,因为volatile属性(如const)参与了过载解析。
这是合法的;这两个重载都是潜在的可调用的,并且作用几乎相同。演员阵容
请注意,代码实际上从不依赖于
|
|
|
11
6
|
|
12
4
这个
对象声明为
考虑以下情况 1) 由作用域外的中断服务例程修改的全局变量。 2) 多线程应用程序中的全局变量。 如果我们不使用volatile限定符,可能会出现以下问题 1) 启用优化后,代码可能无法按预期工作。 2) 启用和使用中断时,代码可能无法按预期工作。 Volatile: A programmerâs best friend https://en.wikipedia.org/wiki/Volatile_(computer_programming) |
|
|
13
2
其他答案已经提到避免一些优化,以便:
每当你需要一个值看起来来自外部并且不可预测,避免基于已知值的编译器优化,以及当一个结果实际上没有被使用但你需要计算它,或者它被使用了但你想为基准计算几次,并且你需要计算在精确的点上开始和结束时,Volatile是必不可少的。
易失性读取类似于输入操作(如
易失性写入类似于输出操作(如
所以 一对易失性读/写可用于驯服基准测试,使时间测量有意义 . 没有volatile,你的计算可以在之前由编译器启动, 因为没有什么能阻止使用时间测量等函数对计算进行重新排序 . |
|
|
14
2
所有的答案都很好。但最重要的是,我想分享一个例子。 下面是一个小cpp程序:
现在,让我们生成上述代码的程序集(我将仅粘贴此处相关的程序集部分): 生成程序集的命令:
以及组装:
您可以在程序集中看到,没有为生成程序集代码
当外部进程/硬件改变以下值时,就会出现问题
现在,为了解决这个问题,在
在这里,您可以看到以下部件代码
|
|
|
15
2
除了volatile关键字用于告诉编译器不要优化对某些变量的访问(这些变量可以由线程或中断例程修改)之外,它还可以 用于删除一些编译器错误 -- 是的,可以 ---. 例如,我在一个嵌入式平台上工作,编译器对变量的值做出了一些错误的假设。如果代码没有优化,程序就会正常运行。有了优化(这是非常必要的,因为这是一个关键的例程),代码就不能正常工作。唯一的解决方案(尽管不是很正确)是将“错误”变量声明为volatile。 |
|
|
16
1
即使没有,你的程序似乎也能正常工作
如前所述
但是,一旦调用外部或非内联函数,似乎几乎没有效果。例如。:
然后有或没有
只要g()可以完全内联,编译器就可以看到正在发生的一切,因此可以进行优化。但是,当程序调用编译器无法看到发生了什么的地方时,编译器再做出任何假设都是不安全的。因此,编译器将生成始终直接从内存读取的代码。
但要小心,当你的函数g()变为内联时(要么是由于显式更改,要么是由于编译器/链接器的聪明),如果你忘记了
因此,我建议添加
|