问题

我在记忆映射硬件寄存器、ISR和多线程程序中读到了C volatile关键字的使用情况.

1) 登记

 uint8_t volatile * pReg;
while (*pReg == 0) { // do sth } // pReg point to status register 
 

(2) 科学研究院

 int volatile flag = 0;
int main() 
{
    while(!flag) { // do sth }
}
interrupt void rx_isr(void)
{
    //change flag
}
 

3)多线程

 int volatile var = 0;
int task1()
{
    while (var == 0) { // do sth }
}
int task2()
{
    var++;
}
 

我可以看到为什么编译器可以错误地优化while在情况1中)如果volatile不在那里,’因为变量是从硬件进行的,编译器可能看不到从代码进行的变量的任何更改.

但对于案例2和3),为什么需要挥发性?在这两种情况下,变量都被声明为全局,编译器可以看到它在不止一个地方使用.那么如果变量不是volatile,为什么编译器会优化while循环?

是因为编译器副设计不知道“异步调用”(在ISR的情况下)或多线程?但这不能,对吗?

此外,案例3)看起来像多线程中的常见程序,没有volatile关键字.假设我将一些锁定添加到全局变量(没有volatile关键字):

 int var = 0;
int task1()
{
    lock();   // some mutex
    while (var == 0) { do sth }
    release()
}
int task2()
{
    lock();
    var++;
    release();
}
 

对我来说它看起来足够正常.那么我真的需要volatile在多线程中吗?如何从未见过volatile限定符添加到变量以避免在多线程程序中优化?

  最佳答案

使用volatile关键字的主要要点是阻止编译器生成使用CPU寄存器作为表示变量的更快方式的代码.这迫使编译代码访问每次访问变量的RAM中的确切内存位置,以获得可能被另一个实体更改的最新值.通过添加volatile,我们确保我们的代码知道任何其他人对变量的任何更改,如硬件或ISR,并且没有发生一致性问题.

在没有volatile关键字的情况下,编译器尝试通过将变量的内容从RAM读入CPU寄存器一次并在循环或函数中使用该缓存值来生成更快的代码.访问RAM可能比访问CPU寄存器慢几十倍.

我有关于项目1和2的经验,但我认为你不需要在多个三环境中定义一个变量为volatile.添加锁/解锁机制是解决同步问题所必需的,并且与volatile的关系没有关系.

  相同标签的其他问题

cmultithreadingembedded