【问题标题】:C: Using static volatile with "getter" function and interruptionsC:使用带有“getter”功能和中断的静态易失性
【发布时间】:2017-10-10 21:49:55
【问题描述】:

假设我有以下 C 代码:

/* clock.c */

#include "clock.h"

static volatile uint32_t clock_ticks;

uint32_t get_clock_ticks(void)
{
    return clock_ticks;
}

void clock_tick(void)
{
    clock_ticks++;
}

现在我在中断内调用clock_tick(即:递增clock_ticks 变量),同时从main() 函数调用get_clock_ticks()(即:在中断外)。

我的理解是clock_ticks 应该声明为volatile,否则编译器可以优化它的访问并使main() 认为值没有改变(虽然它实际上是从中断中改变的)。

我想知道是否在那里使用get_clock_ticks(void) 函数,而不是直接从main() 访问变量(即:不将其声明为static)实际上可以强制编译器从内存中加载变量,即使它是未声明为 volatile。

我想知道这是因为有人告诉我这可能会发生。这是真的吗?在什么条件下?如果我使用“getter”函数,我是否应该始终使用volatile

【问题讨论】:

  • volatile 在您的情况下是必不可少的。从中断访问变量时会有所不同。这样编译器就知道有东西正在访问和修改它不知道的变量。否则,您的“getter”将(可能)返回变量的常量初始值。
  • getter 函数可能会被内联。可能存在可能表现为非确定性行为的缓存一致性问题。
  • @EugeneSh。谢谢你的评论!您介意添加一个答案来解释为什么 getter 没有任何区别吗?
  • @jxh 感谢您的评论!您介意添加一个答案来解释为什么 getter 没有任何区别吗?

标签: c embedded interrupt volatile


【解决方案1】:

getter 函数在这里对使用 volatile 没有任何帮助。

  • 假设编译器看到您刚刚获取了上面两行的值,并且此后没有更改它。
  • 如果它是一个好的优化编译器,我希望它看到函数调用没有副作用,只需优化函数调用即可。

如果get_clock_ticks() 将是external(即在一个单独的模块中),情况就不同了(也许这就是你所记得的)。

在正常程序流程之外(例如在 ISR 中)可以改变其值的东西应该总是声明为volatile

【讨论】:

  • 感谢您的回答。等到明天再接受,以防有人想在这里添加一些东西。 ^^
  • 显示的代码来自文件clock.c,包括一个标题clock.h。使用时钟函数的代码(例如包含 main() 的文件)将只包含标题,并且没有机会内联任何一个函数。当然,没有什么可以阻止 OP 包含 clock.c 文件,但这不是预期的。 (代码也没有显示如何设置中断等)
  • @JonathanLeffler 你以为我们已经看过所有的“clock.c”了吗?我不一定会。从外部或内部“clock.c”调用get_clock_ticks() 时,优化选项会有所不同(这会使事情变得更糟,因为“不起作用”会变成“有时似乎起作用”)
  • 实际上,我指出我们可能还没有看到所有clock.c。我的意思是clock.c 可能是一组库函数的源文件,所提供功能的使用者完全在其他源文件中,而这些文件看不到这些源文件函数,所以没有机会内联代码。当然,OP 可能正在clock.c 中编写他们的整个程序;我建议这不太可能(尤其是因为如果没有其他文件使用clock.c 中定义的函数,clock.h 标头中没有任何意义)。
  • 同意不太可能所有程序都在“clock.c”中。但是你和我都不能 100% 确定 get_clock_ticks() 永远不会从“clock.c”内部调用?一旦它是,它可能会被优化掉。
【解决方案2】:

不要忘记,即使您当前编译声明 get_clock_ticks 的代码和使用它作为单独模块的代码,也许有一天您会使用链接时间或跨模块优化。即使您使用的是 getter 函数,也要保持“易失性”——在这种情况下,它不会对代码生成造成损害,并使代码正确。

您没有提到的一件事是处理器的位大小。如果它不能在单个操作中读取 32 位值,那么您的 get_clock_ticks() 有时会失败,因为读取不是原子的。

【讨论】:

  • 谢谢。是的,它是 32 位 ARM。
猜你喜欢
  • 1970-01-01
  • 2011-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-29
相关资源
最近更新 更多