ACCESS_ONCE的作用
如果你看过 Linux 内核中的 RCU 的实现,你应该注意到了这个叫做 ACCESS_ONCE() 宏。
ACCESS_ONCE的定义如下:
#define __ACCESS_ONCE(x) ({ \
__maybe_unused typeof(x) __var = (__force typeof(x)) ; \
(volatile typeof(x) *)&(x); })
#define ACCESS_ONCE(x) (*__ACCESS_ONCE(x))
仅从语法上讲,这似乎毫无意义,先取其地址,在通过指针取其值。而实际上不然,多了一个关键词 volatile,所以它的含义就是强制编译器每次使用 x 都从内存中获取。
原因:
可以通过几个例子看一下。
1. 循环中有每次都要读取的全局变量:
…
static int should_continue;
static void do_something(void);
…
while (should_continue)
do_something();
假设 do_something() 函数中并没有对变量 should_continue 做任何修改,那么,编译器完全有可能把它优化成:
…
if (should_continue)
for (;;)
do_something();
这很好理解,不是吗?对于单线程的程序,这么做完全没问题,可是对于多线程,问题就出来了:如果这个线程在执行do_something() 的期间,另外一个线程改变了 should_continue 的值,那么上面的优化就是完全错误的了!更严重的问题是,编译器根本就没有办法知道这段代码是不是并发的,也就无从决定进行的优化是不是正确的!
这里有两种解决办法:1) 给 should_continue 加锁,毕竟多个进程访问和修改全局变量需要锁是很自然的;2) 禁止编译器做此优化。加锁的方法有些过了,毕竟 should_continue 只是一个布尔,而且退一步讲,就算每次读到的值不是最新的 should_continue 的值也可能是无所谓的,大不了多循环几次,所以禁止编译器做优化是一个更简单也更容易的解决办法。我们使用 ACCESS_ONCE() 来访问 should_continue:
…
while (ACCESS_ONCE(should_continue))
do_something();
2. 指针读取一次,但要dereference多次:
…
p = global_ptr;
if (p && p->s && p->s->func)
p->s->func();
那么编译器也有可能把它编译成:
…
if (global_ptr && global_ptr->s && global_ptr->s->func)
global_ptr->s->func();
你可以谴责编译器有些笨了,但事实上这是C标准允许的。这种情况下,另外的进程做了 global_ptr = NULL; 就会导致后一段代码 segfault,而前一段代码没问题。同上,所以这时候也要用 ACCESS_ONCE():
…
p = ACCESS_ONCE(global_ptr);
if (p && p->s && p->s->func)
p->s->func();
3. watchdog 中的变量:
for (;;) {
still_working = ;
do_something();
}
假设 do_something() 定义是可见的,而且没有修改 still_working 的值,那么,编译器可能会把它优化成:
still_working = ;
for (;;) {
do_something();
}
如果其它进程同时执行了:
for (;;) {
still_working = ;
sleep();
if (!still_working)
panic();
}
通过 still_working 变量来检测 wathcdog 是否停止了,并且等待10秒后,它确实停止了,panic()!经过编译器优化后,就算它没有停止也会 panic!!所以也应该加上 ACCESS_ONCE():
for (;;) {
ACCESS_ONCE(still_working) = ;
do_something();
}
ACCESS_ONCE的作用的更多相关文章
- if __name__== "__main__" 的意思(作用)python代码复用
if __name__== "__main__" 的意思(作用)python代码复用 转自:大步's Blog http://www.dabu.info/if-__-name__ ...
- (转载)linux下各个文件夹的作用
linux下的文件结构,看看每个文件夹都是干吗用的/bin 二进制可执行命令 /dev 设备特殊文件 /etc 系统管理和配置文件 /etc/rc.d 启动的配置文件和脚本 /home 用户主目录的基 ...
- github中的watch、star、fork的作用
[转自:http://www.jianshu.com/p/6c366b53ea41] 在每个 github 项目的右上角,都有三个按钮,分别是 watch.star.fork,但是有些刚开始使用 gi ...
- web.xml中welcome-file-list的作用
今天尝试使用struts2+ urlrewrite+sitemesh部署项目,结果发现welcome-file-list中定义的欢迎页不起作用: <welcome-file-list> & ...
- web.xml中load-on-startup的作用
如下一段配置,熟悉DWR的再熟悉不过了:<servlet> <servlet-name>dwr-invoker</servlet-name> <ser ...
- SQLSERVER中NULL位图的作用
SQLSERVER中NULL位图的作用 首先感谢宋沄剑提供的文章和sqlskill网站:www.sqlskills.com,看下面文章之前请先看一下下面两篇文章 SQL Server误区30日谈-Da ...
- 电容与EMC-电容不同功能时对整板EMC的作用
一般我们的pcb板的器件有很多种类,但是值得特别关注的,很多人都会说是BGA.接口.IC.晶振之类,因为这些都是layout功能模块以及设计难点.然而数量上占绝对优势的器件却是阻容器件,之前围殴阻抗时 ...
- FTP的搭建与虚拟目录作用<之简单讲解>
操作系统:win7 VS2010编写WebService与在IIS的发布<之简单讲解>中我已经说了IIS安装与使用,不明白的可以跳过去看. 1.添加FTP站点 2. 3. 4. 5. zq ...
- 火狐浏览器中event不起作用解决办法--记录(一)
今天遇到了这个问题.IE,谷歌下都没问题,但在FF下却不起作用,很郁闷查了半天,看别人博文写了老长,结果试了要么起作用,但太麻烦,要么不起作用,说了那么多跟没说一样. 其实只要这一句代码就行:e=ar ...
随机推荐
- vue 入门1 组件管理
全局 组件.局部组件 // Vue.component('todo-list',{ // template:'<li >item</li>' // }); //全局 // va ...
- Python map学习笔记
map是一个高阶用法,字面意义是映射,它的作用就是把一个数据结构映射成另外一种数据结构. map用法比较绕,最好是对基础数据结构很熟悉了再使用,比如列表,字典,序列化这些. map的基本语法如下: m ...
- python对ip地址排序、对列表进行去重
一:使用python对ip地址排序所用代码示例一: import socket iplist = ['10.5.11.1','192.168.1.33','10.5.2.4','10.5.1.3',' ...
- QTP(10)
一.VBS语言基础 1.运算符和表达式 (1)运算符 (2)表达式 a.数学表达式:由算术运算符连接,计算结果为数字 b.字符串表达式:由字符串连接符连接,计算结果为字符串 c.条件表达式:由关系运算 ...
- CSS基础学习-14 CSS visibility与overflow属性
- Mybatis关联查询(转载)
原文地址: http://www.cnblogs.com/xiaolang8762400/p/7399892.html mybatis 提供了高级的关联查询功能,可以很方便地将数据库获取的结果集映 ...
- Linux( Ubantu ) 的简单使用
1.Linux常用的快捷键 Ctrl + Alt+ T --打开终端 Ctrl + Shift + C --复制 Ctrl + Shift + V --粘贴 Ctrl + Shift + A --光标 ...
- 解决nginx无法访问的问题
解决nginx无法访问的问题 解决方案-->恢复Nginx默认配置: cd /usr/local/nginx/conf rm nginx.conf cp nginx.conf.default n ...
- return new Promise的时候,不能带着.then()方法
app.js return new Promise的同时带着.then()方法会出错 return出去的这个Promise,整体状态会显示pending,虽然详细里状态显示resolve,但是没有re ...
- TXNLP 09-17
上节课讲了一些算法的复杂度,都比较简单,我就没有单独截图.1 n n^2 nlogn logn...等等 其实一些排序问题也比较简单.还是给大家列举一下. 归并排序: 主定理定理..吐血 算法复杂度相 ...