ACCESS_ONCE 小记

目的是为了防止编译器优化该变量。

以下面的例子来说,

假如没有ACCESS_ONCE,很可能被优化成:

编译器默认这个变量不会被其它线程修改,出于优化的考虑,为什么不把owner的加载放在循环外呢。

对于一些处理器架构(比如,x86),本身寄存器少,选择哪些变量放在寄存器里非常重要。如果把lock->owner的值直接放在寄存器里,就会出现问题。ACCESS_ONCE()会告诉编译器不要这么做,从而避免可能跟的问题。

ACCESS_ONCE出现的频率可能没有这么多。因为大部分对数据的并发访问都被锁保护着。spinlock和mutex都会起到优化屏障的作用,这意味着它们阻止了屏障一侧的优化延伸到另一侧。如果代码只在持有相关锁的时候访问共享变量,并且变量只在锁被释放(并被其它线程持有)时发生改变,编译器就不会制造这些问题。

只有在访问没有被锁(或显式屏障)保护的共享数据时,像ACCESS_ONCE()这样的构造才是必须的。对于扩展性的考虑会导致产生更多这种类型的代码。