什么时候应该使用volatile 修饰符?
扫描二维码
随时随地手机看文章
volatile 修饰符告诉编译程序不要对该变量所参与的操作进行某些优化。在两种特殊的情况下需要使用volatile 修饰符:第一种情况涉及到内存映射硬件(memory-mapped hardware,如图形适配器,这类设备对计算机来说就好象是内存的一部分一样),第二种情况涉及到共享内存(shared memory,即被两个以上同时运行的程序所使用的内存)。
大多数计算机拥有一系列寄存器,其存取速度比计算机主存更快。好的编译程序能进行一种被称为“冗余装入和存储的删去”(redundant load and store removal)的优化,即编译程序会·在程序中寻找并删去这样两类代码:一类是可以删去的从内存装入数据的指令,因为相应的数据已经被存放在寄存器中;另一种是可以删去的将数据存入内存的指令,因为相应的数据在再次被改变之前可以一直保留在寄存器中。
如果一个指针变量指向普通内存以外的位置,如指向一个外围设备的内存映射端口,那么冗余装入和存储的优化对它来说可能是有害的。例如,为了调整某个操作的时间,可能会用到下述函数:
time_t time_addition(volatile const struct timer * t, int a)
{
int n;
int x;
time_t then;
x=O;
then= t->value
for (n=O; n<1O00; n++)
x=x+a ;
return t->value - then;
}
在上述函数中,变量t->value 实际上是一个硬件计数器,其值随时间增加。该函数执行1000 次把a 值加到x 上的操作,然后返回t->value 在这1000 次加法的执行期间所增加的值。如果不使用volatile 修饰符,一个聪明的编译程序可能就会认为t->value 在该函数执行期间不会改变,因为该函数内没有明确地改变t->value 的语句。这样,编译程序就会认为没有必要再次从内存中读入t->value 并将其减去then,因为答案永远是0。因此,编译程序可能会对该函数进行“优化”,结果使得该函数的返回值永远是0。
如果一个指针变量指向共享内存中的数据,那么冗余装入和存储的优化对它来说可能也是有害的,共享内存通常用来实现两个程序之间的互相通讯,即让一个程序把数据存到共享的那块内存中,而让另一个程序从这块内存中读数据。如果从共享内存装入数据或把数据存入共享内存的代码被编译程序优化掉了,程序之间的通讯就会受到影响。
免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!