volatile
http://blog.myspace.cn/e/402625132.htm
1.
关于 volatile 我觉得这样的解析最容易理解:
如果编译器在代码中发现对同一地址的两次访问之间,没有对该地址进行写操作,那么编译器将优化为第一次寻址读该地址时取得的值作为第二次寻址的值,而并不
是再做第二次物理上的 I/O 寻址操作。volatile 关键字指示编译器进行强制 I/O
寻址,因为编译器那样的优化,可能并不是我们真正期望的,譬如那个地址上连接着一个传感器上的寄存器,那么实际上,可能该寄存器的值是被传感器自身不断刷
新的。因此,我们必要要求CPU每次都进行 I/O 操作。
2.
Why Use Volatile?
The reason to use volatile is to ensure that the compiler generates
code to re-load a data item each time it is referenced in your program.
Without volatile, the compiler may generate code that merely re-uses
the value it already loaded into a register.
Volatile advises the compiler that the data may be modified in a manner
that may not be determinable by the compiler. This could be, for
example, when a pointer is mapped to a device's hardware registers. The
device may independently change the values unbeknownst to the compiler.
Do you volatile? should you?
--by Dr. Kevin P. Dankwardt
原文链接 http://www.linuxdevices.com/articles/AT5980346182.html
3.
volatile 跟以前的 register 相反. register 告诉编译器尽量将变量放到寄存器中使用, 而volatile 强制将更改后的值写回内存(无论是cache还是内存). 如果不写回内存, 对于一些全局共享的变量, 可能导致不一致问题.
volatie 只是编译器优化功能的关键字
4.
volatie变量和cache没有关系,只和内存有关系。
简单点说就是每次操作前从内存取值
有volatie修饰的变量,每次操作时遵循下面动作:
从内存取值 --->
放入寄存器 ---->
操作 ---->
写回内存
没有volatie修饰的变量,操作可能遵循(可能就是不是所有情况都如此):
从内存取值 --->
放入寄存器 ---->
第一次操作 ----->
第二次操作(此时仍操作寄存器中的值) …… ---->
第N次操作 ---->
写回内存
举个例子论述两者关系: int volatie i; //全局变量,在其它地方会被修改 while (i) { do_somethings(); } 如果i没有被volatie修饰,当while循环执行时,另一段程序并发的执行了i=0, 这个循环仍不会退出,因为每次循环都是检查寄存器中的值。 如果有volatie修饰,那么循环结束,因为循环每次检查i的时候,会先从内存把i读入寄存器,这个时候i在其它地方被赋0,则循环结束。 |
5.
这么想就明白了.
编译器在进行对源码编译过程中,通常会对反复使用的变量整个逼本到reg当中从而提高访问速度.由volatile声明的变量,实际上就是通知编译器该变量会以你意想不到的方式被更改,所以你丫别优化我. 那么编译器意想不到的方式有哪几种呢,如下:
1.Memory map的硬件寄存器(比如). 状态寄存器是最常见, 你想呀, 硬件修改这变量他会告诉编译器嘛, 不会也没这能力,
那编译器不就傻呵呵的把该变量优化了嘛, 一优化就坏事了, 因为我们读到的都是reg中存储的旧的状态寄存器的值,
而非memory当中最新的状态寄存器值. 抄个定义给你看看: #define rIICSTAT (*(volatile unsigned
*)0x54000004) //IIC status
2.多线程中被几个线程共享的变量.
线程修改共享变量var会通知编译器嘛,不会也没这能力,所以线程A使劲读着var在reg中的副本(狗日的编译器优化),读出来1时他好大展鸿图呀,结
果读出来的都是0,
而线程B早就把var变量给修改为1了,怪谁呀,只怪没加volatile,加上volatile不早就读memory当中的var新值1了嘛.
3.ISR当中用.这个麻烦,需要拿程序举例,俺就不写了.
6.
一个gcc-volatile的讨论http://gcc.gnu.org/ml/gcc/2007-10/msg00266.html
>
If you really want all externally-visible accesses to v to be made exactly
>
as the code directs, rather than allowing gcc to optimise them in any way that
>
(from the program's POV) it's just the same 'as-if' they had been done
>
exactly, make v volatile.
That is not enough. Apart from the lack of ISO semantics for volatile,
typically a compiler will take volatile as a hint to not hold
values of the variable in a register.
On a multi-processor, this is not enough, because each CPU
may still hold modified values in separate caches.
Perhaps gcc actually puts a RW barrier to force
cache synchronisation on every volatile access..
this seems rather expensive and very hard to do since
it is very dependent on the actual box (not just the
processor). Some processor caches might require external
electrical signals to synchronise, for example. This is
quite possible if you have multiple CPU boards in a box.
But I don't actually know what gcc does, although I guess
it does nothing. The OS has to do the right thing here
when a mutex is locked etc, but the code for that is
probably in the kernel which is better able to manage
things like cache synchronisation than a compiler.
c/c++没有多线程的概念,没有一个明确的memory model,volatile不能保证共享变量在多线称间同步,应该使用明确的lock。