为什么摆脱挥发物是危险的?
在 C++ 中,易失性
的处理方式与 const
相同:将指向易失性数据的指针传递给不需要 易失性
修饰符的函数触发编译错误。
int foo(int* bar) { /* snip */ }
int main()
{
volatile int* baz;
foo(baz); // error: invalid conversion from ‘volatile int*’ to ‘int*’
}
为什么它很危险?对于 const
修饰符来说,删除它显然会破坏 const
的正确性;但是是否存在“易失性
正确性”这样的东西呢?我无法弄清楚将指向易失性数据的指针作为指向非易失性数据的指针传递会如何导致问题。
编辑只是为了让你们知道为什么我首先使用易失性
:许多Mac OS X的OSAtomic
系列函数(用于原子增量、递减、加法、减法、比较和交换等)采用 易失性 参数。
In C++, volatile
is treated the same way const
is: passing a pointer to volatile data to a function that doesn't want the volatile
modifier triggers a compile error.
int foo(int* bar) { /* snip */ }
int main()
{
volatile int* baz;
foo(baz); // error: invalid conversion from ‘volatile int*’ to ‘int*’
}
Why is it dangerous? It's obvious for the const
modifier that removing it can break const
correctness; but is there such a thing as "volatile
correctness"? I can't figure out how passing a pointer to volatile data as a pointer to non-volatile data could cause problems.
EDIT Just so you guys know why I was using volatile
in the first place: many of Mac OS X's OSAtomic
family of functions (for atomic increments, decrements, additions, subtractions, compare and swap, etc.) takes volatile
arguments.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
因为 易失性 修饰符意味着编译器必须注意按照 C 标准的“抽象机器”指定的方式实际执行易失性数据项的每次读/写。
当剥离
易失性
修饰符时,只要程序的行为“好像”发生了访问,只要程序控制流的单线程观点是这样,数据访问就可以被优化。担心的。换句话说,编译器可以将非易失性数据视为编译器并且只有编译器可以看到并可以修改该数据项(绝大多数情况都是这种情况)。volatile
关键字告诉编译器其他东西(硬件或另一个执行线程)可以修改或查看该数据项,因此不允许编译器优化访问。如果您可以在没有警告的情况下将指向易失性数据的指针传递给采用非易失性指针的函数,则该函数可能看不到可能发生的数据更改。如果您不关心这一点,您也许可以编写一个很好的、可移植的解决方法(取决于 foo() 处理数据的方式):
Because the
volatile
modifier means that the compiler must take care to actually perform each read/write of the volatile data item exactly as the C standard's 'abstract machine' specifies.When the
volatile
modifier is stripped away, the data accesses can be optimized away as long as the program behaves 'as if' the access occurred as far as the single-threaded viewpoint of the program flow of control is concerned. In other words, the compiler can treat a non-volatile piece of data as if the compiler and only the compiler can see and can modify the data item (which is the case in the vast majority of cases).The
volatile
keyword tells the compiler that something else (hardware or another thread of execution) can modify or see that data item, so the compiler isn't permitted to optimize away accesses.If you could pass a pointer to a volatile piece of data to a function that took a non-volatile pointer without warning, the function might not see a change in the data that might occur. If you don't care about that, you might be able to code up a nice, portable workaround (depending on what
foo()
does with the data):编译器不仅可以优化对非易失性变量的访问,而且可以预测/推测地更新它们,只要程序的顺序执行不受影响。
如果对易失性变量的虚假写入不会破坏您的设计,则它可能不需要在任何上下文中都是易失性的。
例如,C++03 编译器转换为完全合法
(
尽管这样的更改会提供比仅在少数具有廉价内存访问和很少寄存器的体系结构上注册 sum 更好的性能。我想到的是 Microchip PIC 体系结构.)
Not only can the compiler optimize away access to non-volatile variables, it can update them predictively/speculatively, as long as the sequential execution of the program is unaffected.
If spurious writes to your volatile variable don't break your design, it probably didn't need to be volatile in any context.
For example, it is perfectly legal for the C++03 compiler to transform
into
(Although such a change would provide better performance than enregistering sum only on a few architectures with cheap memory access and very few registers. The Microchip PIC architecture comes to mind.)
好吧,在
foo()
中,编译器不再知道baz
(或更严格地说bar
)是易失性的,因此可能会尝试应用一些不适当的内容优化。Well, in
foo()
the compiler no longer knows thatbaz
(or more strictlybar
) is volatile and so may attempt to apply some inappropriate optimisations.易失性
关键字意味着值应该每次从内存加载和存储到内存。考虑一下代码:
当编译器看到 while 循环时,知道 bar 指向的总是 1。为什么每次都必须检查?如果每次都去检查,那就太浪费了。
易失性
确保编译器确实每次都执行此检查,因此当其他线程更改值时,while
循环退出。The
volatile
keyword means that the value should be loaded and stored from/to memory every time.Consider the code:
When the compiler sees the while loop, and knows that what is pointed to by bar is always going to be 1. Why should it have to check every time? It would be extremely wasteful to check every time.
volatile
makes sure that the compiler does do this check every time, so when the other thread changes the value, thewhile
loop exits.是的,有这样的事情作为“不稳定的正确性”。
它用于帮助确保多线程代码的安全性。
Yes, there is such a thing as "volatile correctness".
It is used to help ensure safety in multithreaded code.