我对C++11内存模型的一点理解(附面经)

来源:互联网 发布:怪物猎人p2g武器数据 编辑:程序博客网 时间:2024/05/16 18:20

    霎时间又到周末,这两天广州天气比较糟糕,一下子雷暴雨一下子又出太阳,夏天到了么- -大学城打雷的时候完全不敢走在路上..感觉随时有被闪电劈中的危险...

    周四周五的时候过去腾讯校招帮忙了,负责收霸面简历,今年感觉竞争很大啊,去年是开了专门的房间给人霸面,今年还要再筛选一次简历,粗略估计前后加起来收到霸面简历应该有接近7,800份,但是最终能霸到的同学应该不多.感慨一下,还是要有多点忧患意识,竞争真心大,人真心多- -不过宿舍周围的兄弟都挺给力的,估计应该都是问题不大的,哈哈.队长小忠贤校招中帮了很多同学忙了,还是灰常给力的,真心这么觉得

    好吧,下面入正题,欢迎各位兄弟批评交流指正.

    最近几天在看C++11相关的一些介绍,主要是从imcc同学翻译的中文faq和里面提到的一些视频.早上看到内存模型那里,说下自己对这个faq部分的理解.

    关于内存模型faq相关资料的连接请猛击:

1.原文地址: http://www2.research.att.com/~bs/C++0xFAQ.html#memory-model

2.翻译地址: http://chenlq.net/cpp11-faq-chinese-version-series-memory-model.html

    摘抄一下重点位置:

Why is this important? Why isn't it obvious? Wasn't this always true? The problem is that when several computations can genuinely run in parallel, that is several (apparently) unrelated instructions can execute at the same time, the quirks of the memory hardware can get exposed. In fact, in the absence of compiler support, issues of instruction and data pipelining and details of cache use will be exposed in ways that are completely unmanageable to the applications programmer. This is true even if no two threads have been defined to share data! Consider, two separately compiled ``threads:''

For greater realism, I could have used the separate compilation (within each thread) to ensure that the compiler/optimizer wouldn't be able to eliminate memory accesses and simply ignore c and b and directly initialize x and y with 1. What are the possible values of x and y? According to C++0x the only correct answer is the obvious one: 1 and 1. The reason that's interesting is that if you take a conventional good pre-concurrency C or C++ compiler, the possible answers are 0 and 0 (unlikely), 1 and 0, 0 and 1, and 1 and 1. This has been observed ``in the wild.'' How? A linker might allocate c and b right next to each other (in the same word) -- nothing in the C or C++ 1990s standards says otherwise. In that, C++ resembles all languages not designed with real concurrent hardware in mind. However, most modern processors cannot read or write a single character, it must read or write a whole word, so the assignment to c really is ``read the word containing c, replace the c part, and write the word back again.'' Since the assignment to b is similar, there are plenty of opportunities for the two threads to clobber each other even though the threads do not (according to their source text) share data!
So, C++0x guarantees that no such problems occur for ``separate memory locations.'' More precisely: A memory location cannot be safely accessed by two threads without some form of locking unless they are both read accesses. Note that different bitfields within a single word are not separate memory locations, so don't share structs with bitfields among threads without some form of locking. Apart from that caveat, the C++ memory model is simply ``as everyone would expect.''

    在原文中举到一个例子,如下:

// thread 1:char c;c = 1;int x = c;// thread 2:char b;b = 1;int y = b;
    BS说,在C++0x的标准当中是可以保证,你在多线程环境当中能够保证x和y分别为1,但是在其他一些编译器(标准)当中可能得到的结果就不是如此,如(0,1), (1, 0), (0, 0).为什么会得到之后的结果?从代码表面上看,两个线程的代码并没有相互影响的部分.

    以32位的机器为例说明,按照上面的代码,b和c都是char型,是一个字节,编译器(liner部分)可能出于某种考虑将b和c放于内存相邻的位置当中.我们假设内存的起始地址为0x0000,内存以字节编号,我们假设c位于内存地址0x0002处,而b位于内存地址0x0003处,如图:


    由于体系的关系(并非所有,但是存在这种可能性),CPU无法一次对一个字节赋值,而是需要读取一个字长(如32位)的内存,更新需要赋值的字节,然后再写入内存,举例来说,如果线程1要更新c的值为1,他读取了0x0000-0x0003的内存,更新0x0002的值为1,之后将这4个字节写入内存当中,这样在多线程环境当中就会带来问题,线程1和线程2都会操纵同一块内存,虽然说修改的只是自己的那一个字节,但是由于其余的3个字节会被覆盖(读取的线程认为他覆盖回去的是原始的内存值),但是事实上这个过程当中有可能另外的线程已经修改了同一块内存区域中其他的字节,存在一个缓存数据(其余3个字节)未被更新的情形,因此才会出现(0,1), (1, 0), (0, 0)这3个非预期的结果,旧的C++标准当中没有考虑到这些问题,而C++11标准则可以保证对内存独立位置(separate memory locations)的操作之间不相互影响.实现的机制可能是引入某种锁机制(个人按照字面意义的猜测).这部分的改进应该也是源于C++11对多线程开发环境的提供了更大支持,毕竟现在多线程开发已经更为常见,标准化进程也是需要与时俱进的^^

    确实,C++11的推出之后,我们应该像学习一门新语言那样再从新学习一下C++.

    末尾的吐槽: 这周去帮忙结果跟老徐汇报工作进度的时候说两个星期内给她一个系统原型,然后下星期还要汇报一篇论文-____-之后两个星期的日子应该是很难熬的了,悲剧啊~~


update 2012-5-25:

localxiao兄弟的理解 -

“另外,你说的这个问题,其实是这样的,C/C++标准,没有规定线程内的局部变量存储位置
也就是说,编译器可以把不同的线程的局部变量存储在一起!而不是分配在不同的线程栈中,这样,就会导致并行操作时候出现问题。

c++0x(应该叫c++1x了吧)对此做了规定,不允许编译器把不同线程的局部变量存储在一起,那么,就可以避开这个问题。

所以,压根不需要啥锁机制”

------------------------------------------------------邪恶分割线----------------------------------------------------

腾讯广州研发部 - 后台开发
一面的时候首先是做题,6道手写代码题,给了我一个钟,要求写的时候要考虑最优的算法

题目如下:
    1. 两个有序链表合并成一个链表
    2. 字符串逆序(要求空间复杂度O(1))
    3. 找出数组中最长的递增序列
    4. 找出排序二叉树中第三大的数(不能完整遍历再输出)
    5. 找出链表中(位置)中间那个元素
    6. 假设A=1,B=2,C=3...AA=27,AB=28...AAA=xxx(表示某个数字),写一个函数统计一个字符串的值是多少


    算法题做完之后开始面试,首先是讲题目思路,没有仔细看代码,不过估计过后是有看的.题目讲完是宇宙第一问,很多人都有问这个问题,就是你做过最难的一个项目是什么,难点在哪里?采取的应该是压力面试,陈述过程中面试官会不断打断你追问他想要知道的细节.这部分过了之后问了实验室方向,提到位置隐私服务的时候让我讲了主要在做的一些相关的理论,追问了一个很多人都问了的问题是如何实现查找附近的K个人(微信的查找附近的人功能).
    接下来问的是Linux方面的知识,首先是Linux系统,文件系统,内存管理和进程管理三大块挑选一个熟悉的讲一讲,然后问了脚本方面相关的,如何用脚本实现IP地址的切换.
    基本就是这样,最后是问了实习的具体时间,整个流程笔试面试耗时2个钟.个人体会是在压力面的时候,对于不懂的问题就表示不懂,不要自己猜测回答.
    二面的时候问的主要都是简历上的项目,没有深入追问,只是了解个大概,之后稍微聊了一下本科和研究生的学习情况,大概10+分钟,然后让我稍等,之后一面面试官过来发了口头offer.over~^_^

原创粉丝点击