vloatile
超详细!!!
单纯的C程序员肯能会很少用到volatile关键字,但是如果说想从事嵌入式的工作,如果不懂得使用volatile,那就基本和offer说拜拜了。本讲内容将详细讲述volatile,为什么要用,什么时候用,有什么注意点…安排!
答应我,硬着头皮也要看完!真的很详细!!!
问题引入
int obj = 10;
int a = 0;
int b = 0;
a = obj;
sleep(100);
b = obj;
//在上述程序中,编译器在编译时发现obj没有被当成左值使用,
//从而“聪明”的编译器会自作主张的将obj替换为10,从而a,b的值都将为10。
这么看来似乎编译器做的并没有什么不对的地方,但是,结合上图,如果说在这休眠的100ms内,正好有一个硬件中断发生,使得obj的值从10——>100,而我们在这里等待100ms的目的就是为了等待这个硬件中断的发生将obj的值从10——>100。这么了看来,编译器自作主张的举动背离了我们的想法。
volatile关键字
一个定义为volatile的变量是说这变量可能会被意想不到的改变,这样,编译器就不会去假设这个变量的值了。
编译器的优化:在本次线程内,当读取一个变量时,为提高存取速度,编译器优化时有时会把变量读取到一个寄存器中,以后再取变量值时,就直接从寄存器中取值;当变量值在本线程内改变时,会同时把变量的新值copy到该寄存器中,以便保值一致。
当变量因在别的线程中等待而改变了值,该寄存器的值不会相应改变,从而造成应用程序读取到的值和实际的变量值不一致。当该寄存器因在别的线程等待而改变了值,原变量的值不会改变,从而造成应用程序读取到的值和实际的变量值不一致。
注:以上内容摘自:https://www.cnblogs.com/reality-soul/p/6140192.html
volatile可以理解为编译器警告指示字;
volatile用于告诉编译器必须每次去内存中取变量值(即:警告它别偷懒,别去取寄存器中的值);
volatile主要修饰可能被多个线程访问的变量;
volatile也可以修饰可能被未知因素更改的变量;
遇到volatile关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
volatile的使用
- 并行设备的硬件寄存器(如:状态寄存器)
存储器映射的硬件寄存器通常要用volatile,因为每次对他的读写都有可能有不同的意义;相关寄存器定义时也会用到volatile,因为这些寄存器中的值是随时变化的,假设存在一个名叫AAA的寄存器,如果未用volatile修饰,那么在使用这个AAA寄存器的时候,会直接从CPU寄存器中取值,因为AAA寄存器之前被访问过,也就是之前就从内存中取出AAA的值保存到某个寄存器中,之所以直接从CPU寄存器中取值而不去内存中取值,是因为编译器优化代码的结果[访问CPU寄存器比访问RAM快得多] - 一个中断服务子程序中会访问到非自动变量
由于访问寄存器比RAM快得多,所以编译器会做减少存取外部RAM的优化,从而导致一些值的变化脱离程序原本的设计意义 - 多线程应用中被几个任务共享的变量
当两个线程中都要用到某一个变量且该变量的值会被改变时,如果不用volatile修饰