ACCESS_ONCE宏定义的解释
作者:linuxer 发布于:2014-7-17 12:34 分类:进程管理
一、ACCESS_ONCE解决什么样的问题
我们首先来看一个代码片段(来自__mutex_lock_common函数,位于linux/kernel/locking/mutex.c文件):
例子1
for (;;) {
struct task_struct *owner;owner = ACCESS_ONCE(lock->owner);
if (owner && !mutex_spin_on_owner(lock, owner))
goto slowpath;
/* ... */
}
这段代码的逻辑比较简单,主要是为临界区加上mutext锁的操作,当已经有其他的thread持有锁的时候,调用本次加锁操作的进程有两个选择:
1、spin直到获取到mutex锁
2、sleep
不同的场景走不同的分支。如果该锁没有pending waiter并且持有锁的thread在另外一个CPU上运行。这种情况下,spin方案会比较好,因此该锁很可能在随后的短时间内被释放。否则,就需要走到slow path去了。因此,在spin的情况下,代码会不断的轮询lock->owner并判断是否owner还持有锁资源,如果当前的owner还占用该资源,那么继续polling,如果锁被释放了,那么程序可以获得锁资源并继续向下执行。c代码虽然好理解,不过c代码和CPU真正执行的代码指令之间还有一个编译器,有些编译器会不择手段的进行优化。例如,对于上面的代码,lock->owner这个变量在for循环中并没有被修改,那么编译器就认为CPU不需要在每一个循环中访问该变量,因此这段代码有可能被编译器优化成:
struct task_struct *owner;
owner = ACCESS_ONCE(lock->owner);
for (;;) {
if (owner && !mutex_spin_on_owner(lock, owner))
break;
/* ... */
}
编译器其实没有那么智能,如果不告诉它,它在编译c代码的时候总是缺省认为只有一个thread在该地址空间中执行。因此,编译器并不知道lock->owner有可能被其他的thread修改的这个事实,因此作出错误的优化(对于single thread,这个优化无疑是正确的)。
在这个例子中,ACCESS_ONCE被c code用来告知编译器在编译的时候,不要因为优化而将多次内存访问合并称为一次。对lock->owner这个memory的访问要确保每个循环都access once。
我们再看另外一个代码片段的例子(来自Linus的邮件):
例子2
if (a > MEMORY) {
do1;
do2;
do3;
} else {
do2;
}
这段代码可能被编译器优化成:
if (a > MEMORY)
do1;
do2;
if (a > MEMORY)
do3;
但是,对于优化后的代码,如果有其他的thread在执行do2的时候修改了MEMORY的值,这时候,CPU执行的代码逻辑和c code是不一致的,或许就会导致问题。
在这个例子中,ACCESS_ONCE这个名字解释就更好理解。也就是说,编译器在编译的时候,不要因为优化而将内存访问拆成多次,确保该内存访问是access once而不是access multi times。
综上所述,ACCESS_ONCE就是用来让c code告诉编译器,这里的内存访问不要优化(不要将多次内存访问合并,对应例子1,也不要将一次内存访问分拆成多次,对应例子2)。
二、代码实现
本身ACCESS_ONCE非常简单,如下:
#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
ACCESS_ONCE本身的实现就是增加了volatile这个关键字,它确保编译器每次访问变量x都是从内存中获取。
原创文章,转发请注明出处。蜗窝科技,http://www.wowotech.net/linux_kenrel/access-once.html
标签: ACCESS_ONCE

功能
最新评论
- wangjing
写得太好了 - wangjing
写得太好了! - DRAM
圖面都沒辦法顯示出來好像掛點了。 - Simbr
bus至少是不是还有个subsystem? - troy
@testtest:只要ldrex-modify-strex... - gh
Linux 内核在 sparse 内存模型基础上实现了vme...
文章分类
随机文章
文章存档
- 2025年4月(5)
- 2024年2月(1)
- 2023年5月(1)
- 2022年10月(1)
- 2022年8月(1)
- 2022年6月(1)
- 2022年5月(1)
- 2022年4月(2)
- 2022年2月(2)
- 2021年12月(1)
- 2021年11月(5)
- 2021年7月(1)
- 2021年6月(1)
- 2021年5月(3)
- 2020年3月(3)
- 2020年2月(2)
- 2020年1月(3)
- 2019年12月(3)
- 2019年5月(4)
- 2019年3月(1)
- 2019年1月(3)
- 2018年12月(2)
- 2018年11月(1)
- 2018年10月(2)
- 2018年8月(1)
- 2018年6月(1)
- 2018年5月(1)
- 2018年4月(7)
- 2018年2月(4)
- 2018年1月(5)
- 2017年12月(2)
- 2017年11月(2)
- 2017年10月(1)
- 2017年9月(5)
- 2017年8月(4)
- 2017年7月(4)
- 2017年6月(3)
- 2017年5月(3)
- 2017年4月(1)
- 2017年3月(8)
- 2017年2月(6)
- 2017年1月(5)
- 2016年12月(6)
- 2016年11月(11)
- 2016年10月(9)
- 2016年9月(6)
- 2016年8月(9)
- 2016年7月(5)
- 2016年6月(8)
- 2016年5月(8)
- 2016年4月(7)
- 2016年3月(5)
- 2016年2月(5)
- 2016年1月(6)
- 2015年12月(6)
- 2015年11月(9)
- 2015年10月(9)
- 2015年9月(4)
- 2015年8月(3)
- 2015年7月(7)
- 2015年6月(3)
- 2015年5月(6)
- 2015年4月(9)
- 2015年3月(9)
- 2015年2月(6)
- 2015年1月(6)
- 2014年12月(17)
- 2014年11月(8)
- 2014年10月(9)
- 2014年9月(7)
- 2014年8月(12)
- 2014年7月(6)
- 2014年6月(6)
- 2014年5月(9)
- 2014年4月(9)
- 2014年3月(7)
- 2014年2月(3)
- 2014年1月(4)
发表评论: