【问题标题】:Can this volatile access be optimized out?可以优化这种不稳定的访问吗?
【发布时间】:2019-04-03 11:19:54
【问题描述】:

来自ISO/IEC 9899:201x 部分5.1.2.3 程序执行:

2 访问易失性对象,修改对象,修改文件, 或调用执行任何这些操作的函数都是所有方面 效果,即执行状态的变化 环境。表达式的评估通常包括 价值计算和副作用的开始。价值计算 对于左值表达式,包括确定 指定对象。

因此,访问(读\写)一个 volatile 被称为副作用。 让我们继续:

4 在抽象机中,所有表达式都按指定计算 由语义。 实际的实现不需要评估部分 一个表达式,如果它可以推断出它的值没有被使用并且没有 产生了所需的副作用(包括任何由调用 函数或访问 volatile 对象)

因此,如果我读取了 volatile(这是一种副作用),但对读取的获取值不做任何事情,则实际上不需要这种访问并且可以进行优化。

好的,还有:

6 对一致性实现的最低要求是:

  • 对 volatile 对象的访问严格按照 抽象机的规则

  • 在程序终止时,所有数据 写入文件应与执行的结果相同 根据抽象语义的程序会产生。

  • 交互设备的输入和输出动态应发生 如 7.21.3 中所述。这些要求的目的是 无缓冲或行缓冲的输出会尽快出现,以 确保提示消息实际出现在程序之前 等待输入。这是程序的可观察行为。

所以,据我了解,第 4 节是抽象机的规则,而6 节说需要严格按照抽象机规则评估 volatiles (第 4 节是)。因此可以优化读取访问(无需进一步使用获取的值)。

那么,看看这段代码:

volatile int *timer_reg = REGISTER_ADDRESS_CONST;
while (*timer_reg  == 0) {/*empty loop*/}

此代码会阻止执行,直到硬件在timer_reg 指向的地址处产生一个位。该寄存器充当一种定时器,配置为在经过一定时间后升高位。当计时器结束时,忙等待结束并继续执行。

现在,可以优化这个while 循环吗?我已经在网上使用许多具有不同优化级别的编译器进行了尝试,但似乎没有。 我在这里缺少什么吗?据我了解,标准明确表示可以对其进行优化。

编辑:我的意思是,由于 while 循环是空的,编译器可能会认为获取的 volatile 值是不需要的。

【问题讨论】:

  • 正在使用获取的值。
  • @Mat 我已经编辑了问题
  • while 循环的主体是空的,但整个循环却不是。
  • 无法优化可观察行为,访问 volatile 限定类型的对象是可观察行为的一部分(尽管构成对 volatile 限定类型对象的访问是实现定义的)。跨度>

标签: c optimization language-lawyer volatile


【解决方案1】:

因此,如果我在不使用读取的值的情况下读取 volatile(这是一种副作用),则实际上不需要此访问,并且可以优化。

没有。文本说“它的价值没有被使用并且不会产生任何需要的副作用”。它没有说“”。无论您是否使用该值,都会存在副作用 - 访问 volatile 变量。

因此可以优化读取访问(无需进一步使用获取的值)。

没有。

现在,这个while循环可以优化了吗?

没有。指向的数据是 volatile 限定的。在循环中的每一圈,它必须直接从内存中读取*timer_reg。它可能不会优化读取。它可能不会重新订购它。它可能不会缓存它/预取它。

【讨论】:

  • AFAIK,C 标准对 volatile 对象的缓存没有什么可说的。
  • @IanAbbott 显然它根本没有提到内存或硬件,但如果 CPU 缓存易失性对象,一切都会中断。 C标准只是说“对易失性对象的访问严格按照抽象机的规则进行评估”,这可以解释为不允许任何类型的重新排序。预取缓存是一种重新排序的形式,其中值是预先读取的。然后可以说编译器的工作是确保不会发生这种情况。或者,如果编译器无法执行此操作,则硬件可能不适合运行 C 程序。
  • 推测,我的 PC 及其 GCC C 编译器不适合运行 C 程序。
  • @IanAbbott 如果它执行 volatile 限定变量的缓存,那么确实如此。这里的问题是让 C 委员会/gcc 人员/PC 程序员了解 volatile 在硬件相关编程中的重要性。如果我指向一个内存映射的 I/O 寄存器,它就无法将该寄存器值存储在缓存中。
  • 内存映射的 I/O 寄存器通常映射到非缓存区域,但这与编译器无关。更相关的是在多处理器系统中使用 volatile 限定的对象。 PC 在处理器之间具有缓存一致性,因此一个处理器对可缓存内存的写入最终会在其他处理器读取时被看到,尽管它们不一定会按照与写入相同的顺序被看到,除非编译器给出“获取语义” " 易失性读取。 (我知道 Microsoft C 编译器默认情况下会执行此操作,ARM 处理器除外。)
猜你喜欢
  • 1970-01-01
  • 2013-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-24
相关资源
最近更新 更多