volatile关键字的作用十分特别, 它的作用是避免编译器对相应代码进行优化.
e.g.
1 | void fun() { |
然后使用 -O2
编译代码. 尝试去掉代码中的 volatile
关键字, 重新使用 -O2
编译, 并对比去掉 volatile
前后反汇编结果的不同.
Question
如果代码中p指向的地址最终被映射到一个设备寄存器, 去掉volatile可能会带来什么问题?
- 缓存不一致:现代计算机系统中,为了提高性能,会使用缓存来存储经常访问的数据。如果没有
volatile
关键字,编译器可能会将p所指向的寄存器值缓存到 CPU 的寄存器中,而不是每次都从内存中读取。这可能会导致其他线程或设备对该寄存器的修改无法及时被当前线程察觉,从而引发错误的结果。 - 指令重排序:编译器和处理器为了提高性能,可能会对指令进行重排序。在单线程环境下,指令重排序通常不会影响程序的正确性。然而,在多线程或与设备交互的环境中,指令重排序可能会导致意外的结果。如果去掉
volatile
,编译器可能会对与p相关的指令进行重排序,从而破坏了程序的预期行为。 - 设备同步问题:设备寄存器通常与外部设备进行交互,这些设备可能有自己的时序 要求。如果没有
volatile
关键字,编译器可能会对与设备寄存器的访问进行优化,导致无法满足设备的同步要求。这可能会导致设备无法正常工作或产生错误的结果。
Usage
- 中断服务程序中修改的供其它程序检测的变量需要加
volatile
; - 多任务环境下各任务间共享的标志应该加
volatile
; - 存储器映射的硬件寄存器通常也要加
volatile
说明,因为每次对它的读写都可能由不同意义;
Reference
本文作者:jujimeizuo
本文地址: https://blog.jujimeizuo.cn/2024/05/25/volatile/
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0 协议。转载请注明出处!