【发布时间】:2021-03-26 00:48:14
【问题描述】:
我正在阅读 kernel/timer.c 文件的一部分,并遇到了使用 READ_ONCE 的这一部分 以及一条注释,指出使用 READ_ONCE() 可以防止编译器进行多次读取。
/*
* We need to use READ_ONCE() here, otherwise the compiler
* might re-read @tf between the check for TIMER_MIGRATING
* and spin_lock().
*/
tf = READ_ONCE(timer->flags);
if (!(tf & TIMER_MIGRATING)) {
base = get_timer_base(tf);
raw_spin_lock_irqsave(&base->lock, *flags);
if (timer->flags == tf)
return base;
然后我在 SO 上找到了这个问题: Can a compiler read twice from a global variable, instead of storing a local one?
这表明编译器确实会多次读取全局变量。 但是,在这种情况下,共享全局变量被分配给局部非易失性变量。 根据question: $tf 也不能省略。 因此,由于他们将易失性变量(标志)分配给非易失性变量($tf),因此易失性的属性是否也转移到非易失性变量($tf),因此也可以防止 $tf重读?
【问题讨论】:
-
So since they are assigning a volatile variable (flags)。flags不是易变的。flags一个普通的u32。 -
#define __READ_ONCE(x) (*(const volatile __unqual_scalar_typeof(x) *)&(x))
-
是的,但是 flags 不是易变的。如果你会做
tf = timer->flags,那么编译器可能会多次读取它。我不明白,如果多次读取tf,它具有相同的常量值,这不是问题。多次读取timer->flags是有问题的,因为两次读取之间可能会被另一个线程异步修改。 -
@KamilCuk 是的,我的问题来自代码中的评论,如果你去 timer.c 链接,他们有一个 __acquire(timer->lock),我不知道如果它确实获得了锁,因为如果它确实获得了锁,那么计时器->标志将不会在其他地方被修改。
-
不,它没有。那完全是另一回事。它用于分析内核代码。而且是在
{}之前,不在函数体中!
标签: c linux linux-kernel compiler-optimization volatile