c - C/C++ 优化如何影响 volatile 变量?

标签 c gcc optimization

我在使用某些代码时遇到一些问题(见下文)。当所有优化都关闭(-O0)时,代码的行为符合我的预期,但是当我打开优化时,代码的表现并不符合我的预期。因此,我在这里发帖,看看是否有人看到优化开启时代码运行方式不同(不正确)的原因。让我解释一下代码的作用...

TPM0->CNT 是一个定时器寄存器,属于 volatile uint32_t 类型。当 TPM0->CNT 达到最大值并翻转时,会生成中断。在此中断内,sg_CpuCount 按自上次中断以来经过的定时器周期数递增。

GetCpuCount 函数的工作是返回瞬时计数(即 sg_CpuCount + TPM0->CNT),但是由于中断可能随时发生并且计时器不会停止,因此在读取/计算此值时必须小心。读取两个组件,然后再次测试第一个组件以查看它是否发生变化。如果它改变了,则在第一次和第二次读取之间触发一个中断,并且重复该过程,但是如果它们相同,则知道没有发生中断,并且返回组件的添加。

逻辑合理吗?优化是否会产生糟糕的代码?有什么见解吗?提前致谢!

编辑:我应该提到优化开启时我注意到的行为。基本上,对 GetCpuCount 的后续调用并不总是像优化关闭时那样单调增加。也就是说,稍后调用 GetCpuCount 可能会返回比之前调用更小的数字 - 这是不可能的。

edit2:我应该提到运行此代码的微型计算机是 32 位架构(并且我使用的是 64 位值)。我仍然认为应该没问题,但这是一个需要考虑的问题。

static volatile int64_t sg_CpuCount;

void TPM0_IRQHandler(void)
{
   TPM0->SC |= TPM_SC_TOF(1); //clear interrupt flag
   sg_CpuCount += CPU_CLOCK / TICKRATE_HZ;
}

int64_t GetCpuCount(void)
{
   for (;;) {
      int64_t tmpCpuCount = sg_CpuCount;
      uint32_t tmpCnt = TPM0->CNT;
      if (tmpCpuCount == sg_CpuCount) {
         return tmpCpuCount + tmpCnt;
      }
   }
}

edit3:添加asm

优化(-0s)

GetCpuCount:
.LFB36:
    .loc 2 80 0
    .cfi_startproc
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 0, uses_anonymous_args = 0
    push    {r4, r5, r6, lr}
    .cfi_def_cfa_offset 16
    .cfi_offset 4, -16
    .cfi_offset 5, -12
    .cfi_offset 6, -8
    .cfi_offset 14, -4
.LBB2:
    .loc 2 82 0
    ldr r4, .L20
    .loc 2 83 0
    ldr r6, .L20+4
.L18:
    //int64_t tmpCpuCount = sg_CpuCount;
    ldr r0, [r4]
    ldr r1, [r4, #4]
    //uint32_t tmpCnt = TPM0->CNT;
    ldr r5, [r6, #4]
    //if (tmpCpuCount == sg_CpuCount) {
    ldr r2, [r4]
    ldr r3, [r4, #4]
    cmp r0, r2
    bne .L18
    cmp r1, r3
    bne .L18
    //return tmpCpuCount + tmpCnt;
    movs    r0, r5
    movs    r1, #0
.LBE2:
    .loc 2 88 0
    @ sp needed
.LBB3:
    .loc 2 85 0
    adds    r0, r0, r2
    adcs    r1, r1, r3
.LBE3:
    .loc 2 88 0
    pop {r4, r5, r6, pc}
.L21:
    .align  2
.L20:
    .word   sg_CpuCount
    .word   1073971200
    .cfi_endproc

未优化 (-00)

GetCpuCount:
.LFB36:
    .loc 2 80 0
    .cfi_startproc
    @ args = 0, pretend = 0, frame = 16
    @ frame_needed = 1, uses_anonymous_args = 0
    push    {r4, r7, lr}
    .cfi_def_cfa_offset 12
    .cfi_offset 4, -12
    .cfi_offset 7, -8
    .cfi_offset 14, -4
    sub sp, sp, #20
    .cfi_def_cfa_offset 32
    add r7, sp, #0
    .cfi_def_cfa_register 7
.L19:
.LBB2:
    //int64_t tmpCpuCount = sg_CpuCount;
    ldr r3, .L21
    ldr r4, [r3, #4]
    ldr r3, [r3]
    str r3, [r7, #8]
    str r4, [r7, #12]
    //uint32_t tmpCnt = TPM0->CNT;
    ldr r3, .L21+4
    ldr r3, [r3, #4]
    str r3, [r7, #4]
    //if (tmpCpuCount == sg_CpuCount) {
    ldr r3, .L21
    ldr r4, [r3, #4]
    ldr r3, [r3]
    ldr r0, [r7, #8]
    cmp r0, r3
    bne .L19
    ldr r0, [r7, #12]
    cmp r0, r4
    bne .L19
    //return tmpCpuCount + tmpCnt;
    ldr r3, [r7, #4]
    movs    r1, r3
    movs    r3, #0
    movs    r2, r3
    ldr r3, [r7, #8]
    ldr r4, [r7, #12]
    adds    r3, r3, r1
    adcs    r4, r4, r2
.LBE2:
    .loc 2 88 0
    movs    r0, r3
    movs    r1, r4
    mov sp, r7
    add sp, sp, #20
    @ sp needed
    pop {r4, r7, pc}
.L22:
    .align  2
.L21:
    .word   sg_CpuCount
    .word   1073971200
    .cfi_endproc

最佳答案

如果您使用的是 32 位计算机,则无法保证 64 位操作是原子的。由于优化,时间可能会发生变化。并且永远不要在禁用中断的情况下调用该函数。

static volatile uint32_t sg_CpuCount;

void TPM0_IRQHandler(void)
{
   TPM0->SC |= TPM_SC_TOF(1); //clear interrupt flag
   sg_CpuCount++; //count interrupts
}

int64_t GetCpuCount(void)
{
   for (;;) {
      uint32_t tmpCpuCount = sg_CpuCount;
      uint32_t tmpCnt = TPM0->CNT;
      if (tmpCpuCount == sg_CpuCount) {
         return (int64_t)tmpCpuCount * CPU_CLOCK / TICKRATE_HZ + tmpCnt;
      }
   }
} 

关于c - C/C++ 优化如何影响 volatile 变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43896407/

相关文章:

algorithm - 将 m 个学生影响到 n 个组,但有限制?

typescript : Object Equality Comparison (Object Equals Object)

c - 释放了 BST 但仍然出现内存泄漏 C

基于fork()的c服务器练习

c - Realloc 在 while 循环中不起作用

c - pthread_mutex_lock 是否包含内存栅栏指令?

c - 错误 : expected ‘=’ , ‘,’ 、 ‘;’ 、 ‘asm’ 或 ‘__attribute__’ 之前

c - 给定堆栈和寄存器的状态,我们能否预测 printf 未定义行为的结果

java代码优化,会不会优化这个

c linux find命令直接返回路径