还是说Memory Model,gcc的__sync_synchronize真是太坑爹了
还是说Memory Model,gcc的__sync_synchronize真是太坑爹了!
嗯,还是说可见性的问题。由于CPU和编译器的乱序执行功能,我们经常不得不在代码中手动插入memory barrier。如果你还不清楚memory barrier是什么,那么请先读这个 http://en.wikipedia.org/wiki/Memory_barrier
假如你已经了解它了,那么具体怎么用呢?怎么在代码中插入一个memory barrier ? 用哪个函数?
gcc的手册中有一节叫做”Built-in functions for atomic memory access”,然后里面列举了这样一个函数:
__sync_synchronize (…)
This builtin issues a full memory barrier.
来,我们写段代码试下:
int main(){
|
然后用gcc4.2编译,
# gcc -S -c test.c
然后看对应的汇编代码,
main: |
嗯?Nothing at all !!! 不信你试一试,我的编译环境是Freebsd 9.0 release, gcc (GCC) 4.2.1 20070831 patched [FreeBSD]。
好,我换个高版本的gcc编译器试一试,gcc46 (FreeBSD Ports Collection) 4.6.3 20120113 (prerelease)
main: |
看,多了一行,mfence。
怎么回事呢?这是gcc之前的一个BUG:http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36793 。 2008年被发现,然后修复的。其实它之所以是一个BUG,关键在于gcc的开发者很迷惑,mfence在x86 CPU上到底有没有用?有嘛用?
那么mfence到底能不能提供我们想要的结果呢?
Intel的手册中有这么一段我一直没太读懂:
“Processors are free to fetch and cache data speculatively from regions of system memory that use the WB, WC, and WT memory types. This speculative fetching can occur at any time and is not tied to instruction execution. Thus, it is not ordered with respect to executions of the MFENCE instruction; data can be brought into the caches speculatively just before, during, or after the execution of an MFENCE instruction. Processors are free to fetch and cache data speculatively from regions of system memory that use the WB, WC, and WT memory types. This speculative fetching can occur at any time and is not tied to instruction execution. Thus, it is not ordered with respect to executions of the MFENCE instruction; data can be brought into the caches speculatively just before, during, or after the execution of an MFENCE instruction.”
但是在关于Memory Ordering的章节又说:
“Reads cannot pass earlier MFENCE instructions
Writes cannot pass earlier MFENCE instructions.
MFENCE instructions cannot pass earlier reads or writes”
综合起来的意思是,如果代码是这样,
READ A
MFENCE
READ B
那么可能会成为这样
READ A
Speculative READ B
MFENCE
但是不会成为这样
Speculative READ B
READ A
MFENCE
也就是说,Speculative READ可以穿越mfence,但是无法走的更远了,不能再穿越前面的读写的操作。所以无论如何,A、B的读取顺序还是被严格保持的。不知道我的理解对不对。
但是这些只是针对单CPU而言。多CPU(包括超线程和多核)的时候,如果还是用Locked instructions,那么没问题。否则手册里的规则没有特别提到mfence,而是说了这么一句,”Memory ordering obeys causality (memory ordering respects transitive visibility).” Causality 也是一种relaxed Model,我不是很能理解。只看到一句通俗点的解释,” If i see it and tell you about it , then you will see it too.”
这个改动对JAVA社区的影响巨大。JVM通过插入mfence指令,使得volatile变量的写入操作,能得到sequential consistency。于是Java社区现在就只有两条路,要么修改语言规范,要么把mfence换成代价更高的xchg指令。David Dice(transactional memory的TL/TL2算法的发明人)的这篇日志http://blogs.oracle.com/dave/entry/java_memory_model_concerns_on 那写的是相当的悲苦啊。
如果实在想在代码中使用membar,那么最好是认准某个编译器和某个平台。否则,非常推荐intel tbb。tbb:: atomic_fence()。
嗯,最后说下C/C++中的volatile。如果非要去咬文嚼字的看标准,那么这个关键字对于多线程同步简直一点帮助都没有。那么实际呢?我们发现很多人在C/C++中用这个关键字,而且,他们不是在写驱动,就是普通的用户态的代码。他们真的都错了吗?
看看这段神奇的代码:
http://software.intel.com/en-us/articles/single-producer-single-consumer-queue/
这段代码中,所有的membar都可以去掉,无非是告诉编译器,别乱搞。volatile关键字,在具体某个编译器中的含义,要远比ISO标准中说的要多。
这是我今天用tbb写的一个Singleton:
class StatusCodeManager{
|
虽然无锁化了,但是并不保证构造函数只执行一次。所以我一直在愁,value->init();插在哪里好呢?
(p.s. 今天找paper的时候看到一篇让我满眼冒金星的神文:《Mathematizing C++ Concurrency》 http://www.cl.cam.ac.uk/~pes20/cpp/popl085ap-sewell.pdf 第一作者是剑桥的某在读博士。)
还是说Memory Model,gcc的__sync_synchronize真是太坑爹了的更多相关文章
- Java (JVM) Memory Model – Memory Management in Java
原文地址:http://www.journaldev.com/2856/java-jvm-memory-model-memory-management-in-java Understanding JV ...
- memory model
最近看C++11 atomic发现对memory_order很是不理解,memory_order_relaxed/memory_order_consume/memory_order_acquire/m ...
- Keil中Memory Model和Code Rom Size说明
C51中定义变量时如果省略存储器类型,Keil C51编译系统则会按编译模式SMALL.COMPACT和LARGE所规定的默认存储器类型去指定变量的存储区域,无论什么存储模式都可以声明变量在任何的80 ...
- 当我们在谈论JMM(Java memory model)的时候,我们在谈论些什么
前面几篇中,我们谈论了synchronized.final以及voilate的用法和底层实现,都绕不开一个话题-Java内存模型(java memory model,简称JMM).Java内存模型是保 ...
- 【翻译】go memory model
https://studygolang.com/articles/819 原文链接 Introduction The Go memory model specifies the conditions ...
- 并发研究之Java内存模型(Java Memory Model)
Java内存模型JMM java内存模型定义 上一遍文章我们讲到了CPU缓存一致性以及内存屏障问题.那么Java作为一个跨平台的语言,它的实现要面对不同的底层硬件系统,设计一个中间层模型来屏蔽底层的硬 ...
- java学习:JMM(java memory model)、volatile、synchronized、AtomicXXX理解
一.JMM(java memory model)内存模型 从网上淘来二张图: 上面这张图说的是,在多核CPU的系统中,每个核CPU自带高速缓存,然后计算机主板上也有一块内存-称为主内(即:内存条).工 ...
- CUDA ---- Memory Model
Memory kernel性能高低是不能单纯的从warp的执行上来解释的.比如之前博文涉及到的,将block的维度设置为warp大小的一半会导致load efficiency降低,这个问题无法用war ...
- 11 The Go Memory Model go语言内置模型
The Go Memory Model go语言内置模型 Version of May 31, 2014 Introduction 介绍 Advice 建议 Happens Before 在发生之前 ...
随机推荐
- Datastage数据装载报错:Consumed more than 1000000 bytes looking for record delimiter
使用Datastage装载数据时报错如下图: 使用ds进行数据传输时,出现上述问题,最终找到了问题的原因: 我所使用的数据文件比较大,上传到服务器的时候传了80%就出现服务器存储空间不够,我删除以前的 ...
- 详谈 oracle 索引 (笔记)
1.oracle索引空值问题 当在有空值得列上建立单列索引时,如果搜索条件为 is null 在解释计划中可以看到,对于此列oracle并没有使用索引查询: 但是当建立的是多列索引是,就会按照索引来进 ...
- Concurrency Series 1
Difference between Processes and Threads Processes A process has a self-contained execution environm ...
- 【TOP10 APP】这些应用成了AppCan千人大会的焦点
如何评价一款APP的好坏?首先,实用性.一款好的APP,首先要能为用户所用.然后是稳定流畅.闪退.卡顿,这样的APP用起来让人抓狂.再一个,界面美观.视觉主观性,在很大程度上会影响使用情况,毕竟没有人 ...
- Android--从相册中选取照片并返回结果
启动系统相册去选择图片 //从相册中选取的方法 private void selectPhoto(){ Intent intent = new Intent(Intent.ACTION_PICK); ...
- HTTP网页错误代码大全带解释
HTTP网页错误代码大全带解释 HTTP 400 - 请求无效HTTP 401.1 - 未授权:登录失败HTTP 401.2 - 未授权:服务器配置问题导致登录失败HTTP 401.3 - ACL 禁 ...
- Python字节流打包拆包
Python提供了一个struct模块用于打包拆包 -------------------------------------------------------------------------- ...
- webservice soapclient报错Error fetching http headers
设置: ini_set('default_socket_timeout', 600); // or whatever new value you want 参考:http://stackoverflo ...
- 嗨分享-前端技术-帝国CMS手机站修改列表分页(sysShowListMorePage)
http://bbs.phome.net/showthread-31-318753-0.html 如果你的网站使用的是帝国CMS.PC站和手机站各使用一个模板组,但共同使用一个数据库.那么你的PC站和 ...
- EF之高级查询
首先我们来看看一个页面 这里面有多选的条件,大于,小于等等,包括每个字段都有 如此多的查询条件,我们的后台该如何实现呢? 难道我们还得每个参数都去判断吗? 那得传多少参数进来才能实现这个页面的功能啊! ...