Are global variables refreshed between function calls?

感情迁移 提交于 2019-12-06 21:26:08

问题


Im writing embedded firmware, and find it sometimes hard to decide when I need volatile or not.

When I have a function that waits for some boolean flag to be changed by an interrupt, it's obvious that the flag needs to be volatile, because else the function would wait forever, since the compiler doesn't realise the value can be changed by the interrupt.

But when I have a short function that just checks a flag in the first line, I would expect the flag doesnt need to be volatile, because its value will be read every time I enter the function? So when an interrupt modifies its value between the first time I call the function, and the second time, I will get the fresh value. Or is it not guaranteed that every time I enter the function all caching registers are cleared?


回答1:


You would still need to mark your variable volatile: since the optimizer is free to inline your functions, especially the short ones, calling your function in a loop without a volatile mark for accessing hardware-modified memory would place you in danger of not reading the memory after the initial iteration.




回答2:


...because its value will be read every time I enter the function?

No, there is no guarantee for this. The problem with the "lack of volatile bug" is that the compiler's optimizer, unaware of that a certain variable can get changed from an external source, changes the whole meaning of the code.

So if you have this:

static int x=0;

int func (void)
{
  if(x == 0)
  {
    return 1;
  }
  else
  {
    return 0;
  }
}

interrupt void isr (void)
{
  x = SOMETHING;
}

Then the compiler will ponder: "Hmm, x is never modified anywhere, since "isr" is never called from the program. So x is always 0, I'll optimize the code to this:"

int func (void)
{
  return 1;
}

And then, perhaps, it will inline the whole function. Whether that happens or not is of no consequence, since the meaning of the code is already destroyed in the previous optimization step.

Any variable shared with an interrupt (or a thread, or DMA, or a hardware register, or a callback function) must be declared as volatile, always.




回答3:


ANY access to a hardware register is best to be marked volatile. The compiler doesn't know that it will be changed via interrupt or DMA from the hardware and the compiler can and will assume it doesn't so it can and will cache certain values.

Essentially if it's hardware mapped or can be changed via interrupt (from hardware) mark it volatile.




回答4:


In addition to marking the variable volatile to force a load (as @dasblinkenlight suggests), you should also take steps to ensure that the variable is read (and written) atomically. On some platforms for certain sized objects (like 32-bit values on recent x86 processors), this happens automatically. In general, you might need to put a synchronization lock around the variable, like a mutex or a semaphore. This is relatively easy to do when the asynchronous code is a thread. I'm not sure what to do when there is a true interrupt involved, as some synchronization techniques might not be possible. Your platform documentation should provide some insight here.




回答5:


All shared memory should be declared volatile.

You may or may not be right that your particular compiler will not optimise out a read in a particular example, but in that case the volatile keyword adds zero overhead (i.e. there is no overhead in specifying an explicit read where it was going to happen in any case), so why risk undefined or non-portable behaviour?



来源:https://stackoverflow.com/questions/14638216/are-global-variables-refreshed-between-function-calls

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!