﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-T9的空间 -随笔分类-Compile &amp; Link</title><link>http://www.cppblog.com/xieshuo/category/20707.html</link><description>You will never walk alone!</description><language>zh-cn</language><lastBuildDate>Mon, 21 Oct 2013 10:14:25 GMT</lastBuildDate><pubDate>Mon, 21 Oct 2013 10:14:25 GMT</pubDate><ttl>60</ttl><item><title>第二章-编译和链接</title><link>http://www.cppblog.com/xieshuo/archive/2013/10/21/203851.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Mon, 21 Oct 2013 09:01:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/10/21/203851.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/203851.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/10/21/203851.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/203851.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/203851.html</trackback:ping><description><![CDATA[<div>第二章</div><div>编译和链接</div><div>这章比较笼统，都是概念，熟悉基本流程的人，建议不看。</div><div>&nbsp;</div><div>记录一些基本流程</div><div>&nbsp;</div><div>拿GCC来说</div><div>用GCC编译链接生成可执行文件的过程分为下面4个步骤</div><div>Prepressing，Compilation，Assembly，Linking</div><div>&nbsp;</div><div>Prepressing 预处理</div><div>从.c -&gt; .i (gcc -E)</div><div>主要是处理，前缀为&#8216;#&#8217;的语句</div><div>&nbsp;</div><div>define的直接替换</div><div>对define这种，从我观察应该是这样</div><div>对源文件类似.c直接扫描 看到define的符号直接加到表中</div><div>然后在替换的时候会做递归检查，直到符号是最终定义。</div><div>&nbsp;</div><div>所以这个与define的顺序没有太大关系了，只要不循环嵌套</div><div>&nbsp;</div><div>类似这种</div><div>#define M (N + 1)</div><div>#define N 2</div><div>&nbsp;</div><div>这种在用到M的时候，会先替换成 （N + 1）但是发现替换的表达式中还有未决symbol，那么</div><div>就再进行替换 （2 + 1）</div><div>&nbsp;</div><div>表中并不会直接写成 M （2 + 1），至少我看到的GCC行为是这样。</div><div>&nbsp;</div><div>include的也是直接导入</div><div>&nbsp;</div><div>另外预编译选项 #ifdef 之类的会处理掉，删掉所有注释</div><div>&nbsp;</div><div>#pragma是要被保留给编译器的，这是编译器选项，例如 pragma pack是用来指定字节对齐标准的</div><div>&nbsp;</div><div>Compilation 编译</div><div>从 .i -&gt; .s (gcc -S)</div><div>现在的GCC版本都把预编译和编译做到了一个可执行程序中 -&gt; ccl</div><div>&nbsp;</div><div>编译的主要过程</div><div>扫描，语法分析，语义分析，源代码优化，代码生成，目标代码优化</div><div>Source code --Scanner--&gt; Tokens --Parser--&gt; Syntax Tree</div><div>--Semantic Analyzer--&gt; Commented Syntax Tree --Source code Optimizer--&gt; Intermediate Representation</div><div>--Code Generator--&gt; Target Code --Code Optimizer--&gt;Final Target Code<br /><div>&nbsp;</div><div>Assembly 汇编</div><div>从 .s -&gt; .o (gcc -c) --&gt;汇编器as</div><div>&nbsp;</div><div>Linking 链接</div><div>ld做的事情</div><div>link的时候由于每个源文件都是单独编译，那么必须处理一些外来的symbol</div><div>包括函数和全局变量</div></div><div></div><img src ="http://www.cppblog.com/xieshuo/aggbug/203851.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xieshuo/" target="_blank"> Torres</a> 2013-10-21 17:01 <a href="http://www.cppblog.com/xieshuo/archive/2013/10/21/203851.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第一章-温故而知新</title><link>http://www.cppblog.com/xieshuo/archive/2013/10/18/203804.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Fri, 18 Oct 2013 11:42:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/10/18/203804.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/203804.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/10/18/203804.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/203804.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/203804.html</trackback:ping><description><![CDATA[<div>第一章</div>
<div>印象:</div>
<div>硬件PCI/ISA的架构</div>
<div>North Bridge相当于人的心脏，连接所有高速设备，CPU -&gt;大脑</div>
<div>南桥芯片则负责低速设备连接<br />&nbsp;&nbsp;</div>
<div></div>
<div>SMP<br />&nbsp;</div>
<div></div>
<div>中间层 是解决很多问题的大方向</div>
<div>Any problem in computer science can be resolved by another layer of indirection<br />&nbsp;<br />CPU密集型 IO密集型</div>
<div>这两种类型的Process，理论上优先级高的，也就是说最应该先得到CPU的是IO密集型</div>
<div></div>
<div>通俗的理解应该是IO密集型做完事情花的CPU时间最少，然后就会等待IO设备的反应，这样可以让设备性能最大化<br />&nbsp;</div>
<div></div>
<div>Memory</div>
<div>分段分页 MMU<br />&nbsp;</div>
<div></div>
<p>线程安全和线程模型<br />&nbsp;</p>
<div>其中线程安全有两件事情要注意</div>
<div>Semaphore</div>
<div>Mutex</div>
<div>上面这两个可以做成全局的，并不一定是By Process的，例如POSIX pthread在</div>
<div>对Mutex做attr设定的时候就可以指定为 shared process</div>
<div>也就是说一个Process可以加锁，另外一个可以释放他。</div>
<div>另外这种Mutex必须处在共享内存中，否则没办法访问。有亲缘关系的Process可以通过mmap一个匿名映射做到</div>
<div>anyway有很多方式了。<br />&nbsp;</div>
<div></div>
<div>Critical Section</div>
<div>这个是Inter Process的东西。<br />&nbsp;</div>
<div></div>
<div>关于线程互斥的lock的问题</div>
<div>RW lock就是对普通lock记录两个状态来供read or write操作选择<br />&nbsp;<br />属于线程本身的东西 TLS/Stack/Register<br />&nbsp;</div>
<div>有时候编译器会为了做优化</div>
<div>内存和寄存器的数据会出现不sync的状态。</div>
<div></div>
<div>即使你用lock来做保护,也不一定能OK。然后volatile就出现了。&nbsp;<br />&nbsp;</div>
<div>volatile最主要的作用就是thread内保证编译器不要做优化，防止这种不sync带来的问题。</div>
<div></div>
<div>一般是这样例如x变量，thread_1读到x变量放到了寄存器中，因为可能马上会再访问它，那么对x进行操作后就不会写回内存</div>
<div>这样即使你加了lock，这个时候lock也被释放掉了（操作完成），但是结果未能Sync，那么thread 2来访问x的时候，在内存</div>
<div>中拿到的值就变成dirty状态了。<br />&nbsp;
</div>
<div></div>
<div>另外一种过度优化就是CPU做的优化，有些上下语义无关的指令，CPU有可能会调整运行顺序。</div>
<div>书中有个经典样例</div>
<div>一段 Singleton pattern的double-check的代码</div>
<div></div>
<div>volatile T* pInst = NULL;</div>
<div>T* getInstance()</div>
<div>{</div>
<div><span style="white-space:pre"> </span>if (pInst == NULL)</div>
<div><span style="white-space:pre"> </span>{</div>
<div><span style="white-space:pre"> </span>lock();</div>
<div><span style="white-space:pre"> </span>if (pInst == NULL)</div>
<div><span style="white-space:pre"> </span>pInst = new T();</div>
<div><span style="white-space:pre"> </span>unlock();</div>
<div><span style="white-space:pre"> </span>}</div>
<div><span style="white-space:pre"> </span>return pInst;</div>
<div>}<br /><br />&nbsp;</div>
<div></div>
<div>这里有两点</div>
<div>第一，double-check 也就是双if能避免过多的无用的get lock，降低消耗</div>
<div>对临界区需要做保护的资源，可以提前去取状态，如果符合自己的预期，而且短时间不会有变化，那么就不用去拿锁了</div>
<div>不知道为啥我想到了unlikely，但仔细想一下，功能完全不同。<br />&nbsp;</div>
<div></div>
<div>第二点也就是要说的CPU的过度优化</div>
<div>这里已经是声明volatile了，所以没有寄存器和内存不sync的问题</div>
<div>但是由于这里new需要先 malloc出空间，然后call T的constructor。</div>
<div>所以有可能会发生这种情况，malloc出空间后，把地址付给pInst，然后去做初始化；</div>
<div>这样就有可能另外一个线程取得的object是没有被完全初始化好的，是否会出问题depend on T的具体实现了。</div>
<div></div>
<div>许多CPU提供了barrier指令用来解决上面提到的问题。<br />&nbsp;</div>
<div></div>
<div></div>
<div>线程模型</div>
<div>这个东西，我看了下，开始没看明白，这边书这个东西没讲清楚，后来去网上找了些资料。用户线程和内核线程的对应关系取决于调度单位。</div>
<div>也就是说内核把什么东西当做一个调度单位<br />&nbsp;</div>
<div>拿Linux来说吧，Process是线程集和资源集<br />&nbsp;</div>
<div>调度的时候，那些共享资源的Task（thread）之间的调度肯定比那些跨Process不共享资源的thread做context switch消耗的资源</div>
<div>多得多。<br />&nbsp;</div>
<div></div>
<div>基于调度消耗之类的考量</div>
<div></div>
<div>模型分为下面几种<br />&nbsp;</div>
<div>一对一，也就是说 user space create出来的线程就是和kernel的调度单位相同，称一一对应<br />&nbsp;</div>
<div>一对多，应该是这样一种情况，kernel看到的是Process，userspace自己实现出来自己的thread，这个thread，kernel是不知道的</div>
<div>调度的时候kernel负责分批CPU给他能看到的Process，上层userspace自己来调度分配这个Process获得的CPU time给这个process中的</div>
<div>各个线程。</div>
<div>这样的分配就可以保证在一定的时间内只需要做一些register和stack的切换，不会有memory等等的switch。</div>
<div>坏处是上面的thread只要一个被suspend，那么这个Process里面的其他thread也就被suspend住了，一般上层调度程序</div>
<div>不会假定其他的thread能run，所以一般会是kernel把CPU time给其他process<br />&nbsp;</div>
<div></div>
<div>多对多，就是一种混合的情况了，我想到了Android，但是Android是一对一模型，dalvik会保证Java thread对应下面一个</div>
<div>native thread，想说的是，这种虚拟机架构可以做成多对多的样子，一个native thread run一个JVM，JVM开出来很多Java Thread，</div>
<div>JVM负责调度这些Java Thread，Native负责调度JVM所在的Thread。</div>
<div>不知道我有没有讲错。<br />
<br />
</div>
<div></div>
<div></div><img src ="http://www.cppblog.com/xieshuo/aggbug/203804.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xieshuo/" target="_blank"> Torres</a> 2013-10-18 19:42 <a href="http://www.cppblog.com/xieshuo/archive/2013/10/18/203804.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员自我修养-读书笔记</title><link>http://www.cppblog.com/xieshuo/archive/2013/10/14/203710.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Mon, 14 Oct 2013 09:07:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/10/14/203710.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/203710.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/10/14/203710.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/203710.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/203710.html</trackback:ping><description><![CDATA[&nbsp; &nbsp; &nbsp;之前就翻过一次，这次再看看，期望这次能读到我想知道的东西...<br />&nbsp; &nbsp; &nbsp;这个书的名字我自己觉得有点屌丝风格了，Orz，期望编者勿怪<img src ="http://www.cppblog.com/xieshuo/aggbug/203710.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xieshuo/" target="_blank"> Torres</a> 2013-10-14 17:07 <a href="http://www.cppblog.com/xieshuo/archive/2013/10/14/203710.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>