计时器溢出竞争条件



我使用的是一个带有16位计时器的微控制器。当前值可以从寄存器中读取。但是我需要一个32位计数器。每当定时器溢出时,它就会产生一个中断。我当前的解决方案如下代码所示。每次计时器溢出时,变量counter_high都会递增。当前计数器值被读取为counter_high和定时器寄存器的组合。

volatile uint16_t counter_high = 0;
uint32_t get_counter(void)
{
return (counter_high << 16) | timer->counter;
}
void timer_overflow(void)
{
counter_high++;
}

这似乎奏效了。然而,我开始怀疑,如果在执行get_counter()时计时器溢出,会发生什么?我可以得到counter_high的旧值与timer->counter的新值的组合,反之亦然。

是否有预防此问题的最佳实践?

在读取timer->counter之前和之后读取counter_high。如果为counter_high读取的值没有更改,则您知道timer->counter在读取之间没有滚动,因此您可以信任从timer->counter读取的值。

但是,如果counter_high在两次读取之间发生了变化,那么您就知道timer->counter在两次读之间的某个时间发生了翻转。这意味着您不能信任从timer->counter读取的值,因为您不知道是在滚动之前还是之后读取的。但现在您知道timer->counter最近刚刚滚动,所以您可以再次阅读它,并知道它不会再次滚动。

uint32_t get_counter(void)
{
uint32_t first_counter_high = counter_high;
uint32_t counter_low = timer->counter;
uint32_t second_counter_high = counter_high;
if (first_counter_high != second_counter_high)
{
counter_low = timer->counter;  // Read timer->counter again, after rollover.
}
return (second_counter_high << 16) | counter_low;
}

最新更新