﻿<?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的空间 -随笔分类-APUE</title><link>http://www.cppblog.com/xieshuo/category/20531.html</link><description>You will never walk alone!</description><language>zh-cn</language><lastBuildDate>Sun, 21 Jul 2013 14:34:27 GMT</lastBuildDate><pubDate>Sun, 21 Jul 2013 14:34:27 GMT</pubDate><ttl>60</ttl><item><title>LTZ看书之APUE14</title><link>http://www.cppblog.com/xieshuo/archive/2013/06/07/200852.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Fri, 07 Jun 2013 10:52:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/06/07/200852.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/200852.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/06/07/200852.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/200852.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/200852.html</trackback:ping><description><![CDATA[伪终端.<br />
<p>这个是Muxd一直用的东西<br />相当于一个双向PIPE<br />Process A open ptm得到fdm，然后fork出process B，process B open pts得到fds，然后将0,1,2都dup到fds上<br />那么fds就变成了process B的控制终端<br />后面再process B中做标准IO操作的时候就会像PIPE直接影响到fdm<br />终端行规程在pts之上<br /><br />没什么特别要记录的，在网上search了下，贴个链接，里面会介绍一些基本概念.<br /><a href="http://www.cnblogs.com/Anker/archive/2012/12/25/2832568.html">http://www.cnblogs.com/Anker/archive/2012/12/25/2832568.html</a> </p><img src ="http://www.cppblog.com/xieshuo/aggbug/200852.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-06-07 18:52 <a href="http://www.cppblog.com/xieshuo/archive/2013/06/07/200852.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LTZ看书之APUE13</title><link>http://www.cppblog.com/xieshuo/archive/2013/06/07/200842.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Fri, 07 Jun 2013 06:40:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/06/07/200842.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/200842.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/06/07/200842.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/200842.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/200842.html</trackback:ping><description><![CDATA[<p>终端IO<br />每个终端都有输入输出队列<br />队列都有长度，如果输入超过输入队列MAX_INPUT长度，大多数unix系统会回显响铃来处理。<br />但是对于输出队列来讲，虽然输出队列也有长度，但是一旦写不进去的时候，写进程会suspend掉<br />直至有空闲空间</p>
<p>终端行规程 terminal line discipline<br />会帮忙做规范处理</p>
<p>终端设备属性 -&gt;termios</p>
<p>struct termios {<br />&nbsp;tcflag_t c_iflag;<br />&nbsp;tcflag_t c_oflag;<br />&nbsp;tcflag_t c_cflag;<br />&nbsp;tcflag_t c_lflag;<br />&nbsp;cc_t c_line;<br />&nbsp;cc_t c_cc[NCCS];<br />};</p>
<p>local flag影响驱动程序和用户之间的接口<br />Android上tcflag_t-&gt;<br />typedef unsigned int tcflag_t;</p>
<p>cc_t<br />typedef unsigned char cc_t;</p>
<p>control flag中很多选项标志都是用几位标识然后用或来做选择</p>
<p>isatty的实现，借助tcgetattr的出错机制，成功返回0；否则返回-1，带上ENOTTY</p>
<p>int<br />isatty (int&nbsp; fd)<br />{<br />&nbsp; struct termios term;</p>
<p>&nbsp; return tcgetattr (fd, &amp;term) == 0;<br />}</p>
<p>Anyway，终端IO很复杂...</p><img src ="http://www.cppblog.com/xieshuo/aggbug/200842.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-06-07 14:40 <a href="http://www.cppblog.com/xieshuo/archive/2013/06/07/200842.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LTZ看书之APUE12</title><link>http://www.cppblog.com/xieshuo/archive/2013/06/06/200830.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Thu, 06 Jun 2013 09:22:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/06/06/200830.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/200830.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/06/06/200830.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/200830.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/200830.html</trackback:ping><description><![CDATA[<p>IPC<br /><br />首先讲到的是PIPE，这个并不陌生，相互通信的Process必须具有关系，一般是同父亲的<br />然后讲到了协同进程<br />基本是说有一个进程专门用来接收输入，然后处理，然后返回结果<br />这个就可以用PIPE来实现</p>
<p>创建两个PIPE，一个用于输入给协同进程，另外一个用于接收协同进程的输出<br />fork之后在子进程中将标准输入输出都dup到管道上</p>
<p>而协同进程的写法可以比较common，只用关心标准输入输出。<br />PIPE在写的时候如果有多个写进程，那么写的数据小于 PIPE_BUF 则不会乱序，否则自己应该就需要做同步了。</p>
<p>然后就是FIFO，这个就是用mkfifo创建一个file，大家都去用。<br />PIPE和FIFO都是半双工的</p>
<p>XSI IPC -&gt;即之前System V IPC<br />消息队列 信号量 共享存储器</p>
<p>在无关进程之间共享存储段，一个是使用上面V系统shm；另外一个是使用mmap将同一文件map到他们自己的进程空间。<br /><br />另外就是网络IPC了<br />算是复习下吧，之前这块儿看的比较多<br />int socket(int domain, int type, int protocol)<br />domain标识address family -&gt; AF_INET, AF_INET6, AF_UNIX(AF_LOCAL), AF_UNSPEC<br />type标识socket类型 -&gt; SOCK_DGRAM(UDP), SOCK_RAW(IP), SOCK_SEQPACKET, SOCK_STREAM(TCP)<br /><br />一般protocol都设置为0，一般address family和type就能确认要使用的protocol<br /><br />SOCK_SEQPACKET和SOCK）STREAM很像，前一个提供面向数据报文的服务，而后面这种则是面对流。<br />SOCK_SEQPACKET使用场景SCTP，贴一个SCTP的简要介绍。<br /><a href="http://www.cnblogs.com/qlee/archive/2011/07/13/2105717.html">http://www.cnblogs.com/qlee/archive/2011/07/13/2105717.html</a><br /><br />涉及网络就必须要清楚字节序的问题，字节序与字符编码是两件不同的事情，都要想清楚的，但是要提一下UTF-8这是一种专门设计用来做网络传输的字符编码<br />无需关心字节序的问题，所以传输的上层数据可以用UTF-8，就不用担心local host和remote host的主机字节序不一样而导致乱序了。<br /><br />但是很多协议头必须做符合TCP/IP协议的字节序规范，TCP/IP是big endian<br />关于Big endian和Litter endian我比较容易忘记具体的样子，但是他的出发点是低地址，低地址装的是最高有效字节那么就是big endian，否则就是litter endian。<br /><br />关于socket有几个可能比较模糊的地方<br />connect时，也就是client端，如果fd没有绑定到某个地址，那么kernel会帮忙将其绑定到默认地址; 所以bind这件事情是Client和Server都需要做的事情，调用listen之前也一样<br />然后accept的时候，如果你关心对方的地址，那么提供addr(足够)和len，返回的时候就能知道。<br />另外UDP(SOCK_DGRAM)也可以Call connect，之后就可以直接call send/write，而不必每次都call sendto指定对端地址。<br /><br />sendto中flag一般给0，如果是紧急数据给MSG_OOB<br /><br />文件描述符的传输，目的是想让不同的process在不同的文件描述符中共享文件表。<br />所以做法上系统会这样，传输文件表指针然后放到接收端的第一个可用的文件描述符上。<br />这个我在linux上没找到实现，因为这个功能还是有蛮多替代方案的。<br /></p>  <img src ="http://www.cppblog.com/xieshuo/aggbug/200830.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-06-06 17:22 <a href="http://www.cppblog.com/xieshuo/archive/2013/06/06/200830.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LTZ看书之APUE11</title><link>http://www.cppblog.com/xieshuo/archive/2013/06/05/200818.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Wed, 05 Jun 2013 08:59:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/06/05/200818.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/200818.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/06/05/200818.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/200818.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/200818.html</trackback:ping><description><![CDATA[<p>13章在讲Daemon Process，没什么特别好写的。<br />14 -&gt;高级IO</p>
<p>低速系统调用，也就是有信号发生会返回 errno 为 EINTR的</p>
<p>磁盘文件IO虽然有延时，但是这个不能算是低速系统调用</p>
<p>APUE介绍的低速系统调用<br />PIPE，终端设备，网络设备 读写 <br />读无数据/写无空间(例如TCP卡Congestion window)</p>
<p>打开某些特殊文件<br />加记录锁的文件读写<br />ioctl，IPC<br /></p>
<p><br />文件锁又叫做 byte-range locking，针对特定的文件区域，适合数据库文件<br />Posix标准<br />int fcntl(int fd, int cmd, .../* struct flock* flockptr */)<br />cmd -&gt; F_GETLK,F_SETLK,F_SETLKW<br />F_SETLKW是F_SETLK的Blocking版本 W means wait</p>
<p>重要数据结构是struct flock -&gt;<br />struct flock {<br />&nbsp;short l_type;<br />&nbsp;short l_whence;<br />&nbsp;off_t l_start;<br />&nbsp;off_t l_len;<br />&nbsp;pid_t l_pid;<br />&nbsp;__ARCH_FLOCK_PAD<br />};</p>
<p>锁定整个file的方式: l_whence = SEEK_SET, l_start = 0, l_len = 0</p>
<p>l_type的两类lock<br />F_RDLCK，F_WRLCK这两种锁的特性很像rw lock</p>
<p>不过与读写锁不一样的是或者这样讲<br />Posix.1没有规定下面这种情况: process A在某文件区间上设置了一把读锁；process B尝试在这个文件区间加上写锁的时候suspend；process C再尝试获取读锁，如果允许</p>
<p>process C拿到读锁，那么process B将会可能永远拿不到写锁，活活饿死</p>
<p>pthread里面的rw lock的实现会在这种情况下suspend掉process C的读锁请求；但是目前文件区域锁的实现我不太确定</p>
<p>这里看文件区域锁还是比较容易带来deadlock的<br />例如process A锁住F1的某个区域，然后去锁F2的一个区域，这时候F2的这个区域被process B锁住，那么process A就会suspend，如果这个时候process B过来要锁F1的这个区域<br />就会发生deadlock<br /></p>
<p><br />关于文件区域锁的继承和释放<br />1.fork后，文件区域锁并不继承，继承了就完了，不同的process就有可能同时干同一件事情，把数据搞坏<br />2.close(fd)后 fd对应的文件锁就被释放了，文件锁挂在inode上，close的时候kernel会去扫描对应的inode上与这个PID相关的lock，释放掉，而并不去关心是哪个文件描述符或</p>
<p>者是哪个文件表，这很重要，因为lockf中并不记录fd，他们只是弱关联关系，这个很重要。<br />3.exec后，文件锁会继承原来执行程序的锁(fork之后拿到的lock)，如果fd带有close-on-exec那么根据第二条，这个fd对应的file上的锁都会被释放。</p>
<p><br />后面讲了STREAMS，感觉linux上用到的不多，需要在编译kernel时动态加载</p>
<p>IO多路转接，主要是为了实现polling既所谓的轮询<br />主要函数有select，pselect，poll，epoll<br />select也会算是低速系统调用，那么就有可能被信号打断<br />pselect有参数可以设定信号屏蔽集，也提供更高精度的timer</p>
<p>poll的方式与select有不太一样的地方，但是功能相同，epoll更适合大数据量。</p>
<p>readv和writev<br />记住下面两条就够了<br />一个称为scatter read(散步读)；另外一个称为gather write(聚集写)<br />这两个函数会面对一个buffer链表。<br /></p>
<p><br />readn和writen<br />这个比较像现在Android里面socket的read和write方式，保证能read/write n byte数据，在内部做循环<br />我比较好奇这两个是否会处理signal，想来应该是会处理的，遇到EINTR帮忙重启就好了</p>
<p>我没有找到Bionic库的实现<br /></p>
<p><br />存储映射IO<br />这个很重要，mmap用的很多，映射到process空间的位置在 stack以下，heap以上的部分，map完后返回低地址。</p>
<p>#include&lt;sys/mman.h&gt;<br />void* mmap(void* addr, size_t len, int prot, int flag, int filedes, off_t off)</p>
<p>prot -&gt; PROT_READ,PROT_WRITE,PROT_EXEC,PROT_NONE<br />prot指定的对映射存储区的保护不能超过文件的open权限</p>
<p>在 flag为 MAP_FIXED的时候OS会保证分配的memory起始地址为addr，否则只是给OS一个建议。<br />一般建议addr给0，让OS来决定。</p>
<p>MAP_SHARED是说对映射区域的存储(write)会导致修改该文件。<br />MAP_PRIVATE则是对映射区域的操作会常见一个映射文件的副本。<br /></p>
<p><br />后面有个例子用了lseek<br />使用lseek增加文件长度的方式，先lseek一个值，如果这个值大于文件本身的长度，那么下一次写就会加长该文件，并且在文件<br />中形成一个空洞，未写过的内容全部读为0。<br />mmap只能map文件的最大长度，超过的地方没办法同步到文件。</p><img src ="http://www.cppblog.com/xieshuo/aggbug/200818.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-06-05 16:59 <a href="http://www.cppblog.com/xieshuo/archive/2013/06/05/200818.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LTZ看书之APUE10</title><link>http://www.cppblog.com/xieshuo/archive/2013/06/04/200788.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Tue, 04 Jun 2013 07:41:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/06/04/200788.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/200788.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/06/04/200788.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/200788.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/200788.html</trackback:ping><description><![CDATA[<p>线程控制</p>
<p>APUE讲的destroy会free空间，这件事情看起来不太对，也许是Base on实现<br />起码我看到的实现是没有做这件事情的。</p>
<p>&nbsp;</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;pthread_attr_init(pthread_attr_t&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;attr)<br /><img id="Codehighlighter1_45_94_Open_Image" onclick="this.style.display='none'; Codehighlighter1_45_94_Open_Text.style.display='none'; Codehighlighter1_45_94_Closed_Image.style.display='inline'; Codehighlighter1_45_94_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_45_94_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_45_94_Closed_Text.style.display='none'; Codehighlighter1_45_94_Open_Image.style.display='inline'; Codehighlighter1_45_94_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span id="Codehighlighter1_45_94_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_45_94_Open_Text"><span style="color: #000000">{<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">attr&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;gDefaultPthreadAttr;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;pthread_attr_destroy(pthread_attr_t&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;attr)<br /><img id="Codehighlighter1_145_209_Open_Image" onclick="this.style.display='none'; Codehighlighter1_145_209_Open_Text.style.display='none'; Codehighlighter1_145_209_Closed_Image.style.display='inline'; Codehighlighter1_145_209_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_145_209_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_145_209_Closed_Text.style.display='none'; Codehighlighter1_145_209_Open_Image.style.display='inline'; Codehighlighter1_145_209_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span id="Codehighlighter1_145_209_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_145_209_Open_Text"><span style="color: #000000">{<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;memset(attr,&nbsp;</span><span style="color: #000000">0x42</span><span style="color: #000000">,&nbsp;</span><span style="color: #0000ff">sizeof</span><span style="color: #000000">(pthread_attr_t));<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span></div>
<p><br />Attribution有下面这些。<br /></p>
<p>&nbsp;</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="color: #000000">typedef&nbsp;</span><span style="color: #0000ff">struct</span><span style="color: #000000"><br /><img id="Codehighlighter1_15_160_Open_Image" onclick="this.style.display='none'; Codehighlighter1_15_160_Open_Text.style.display='none'; Codehighlighter1_15_160_Closed_Image.style.display='inline'; Codehighlighter1_15_160_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_15_160_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_15_160_Closed_Text.style.display='none'; Codehighlighter1_15_160_Open_Image.style.display='inline'; Codehighlighter1_15_160_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span id="Codehighlighter1_15_160_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_15_160_Open_Text"><span style="color: #000000">{<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;uint32_t&nbsp;flags;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;stack_base;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;size_t&nbsp;stack_size;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;size_t&nbsp;guard_size;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;int32_t&nbsp;sched_policy;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;int32_t&nbsp;sched_priority;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="color: #000000">&nbsp;pthread_attr_t;</span></div>
<p>我们可以用malloc和mmap给Thread分配stack，指定stack大小和位置(低地址)</p>
<p>mutex属性<br />两个东西<br />1.进程共享属性，PTHREAD_PROCESS_PRIVATE or SHARED<br />意思是说如果这个Mutex是分配在两个进程共享的memory，然后设置为shared mutex就可以用于进程同步<br />2.类型属性，normal;errorcheck;recurive<br />意思是定义Mutex本身的特性，这里更正下前面那章提到的错误<br />只有normal的mutex才会在再次加锁时发生deadlock<br />errorcheck的会直接返回错误<br />recurive本身就允许，会有计数</p>
<p>rw lock和condition属性<br />只支持第一个<br /><br />TLS变量<br />先看下TLS的位置</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">+---------------------------+</span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">|</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_internal_t&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">|</span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">+---------------------------+</span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">|</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">|</span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">|</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TLS&nbsp;area&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">|</span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">|</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">|</span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">+---------------------------+</span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">|</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">|</span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stack&nbsp;area&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">|</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">|</span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">+---------------------------+</span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">|</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;guard&nbsp;page&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">|</span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">+---------------------------+</span></div>
<p>pthread_internal_t是记录线程自己本身的一些属性的变量，guard page就是线程attr上设置的防止栈溢出的扩展内存<br /><br />创建TLS变量的方法<br />1.创建Key，这个Key是这个Process中所有Thread可以共享访问的，然后每个Thread自己去关联自己的Thread Local变量<br />int pthread_key_create(pthread_key_t *keyp, void (*destructor)(void*))<br />创建key的时候需要保证唯一调用，也就是不会有两个Thread同时调用，然后发生一些base on实现的不确定的结果，可以使用pthread_once<br /><br />pthread_once的实现很简单，用mutex做互斥量保证pthread_once_t的访问，然后利用pthread_once_t做flag来调用init_routine</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;&nbsp;pthread_once(&nbsp;pthread_once_t</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;&nbsp;once_control,&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;(</span><span style="color: #000000">*</span><span style="color: #000000">init_routine)(</span><span style="color: #0000ff">void</span><span style="color: #000000">)&nbsp;)<br /><img id="Codehighlighter1_80_574_Open_Image" onclick="this.style.display='none'; Codehighlighter1_80_574_Open_Text.style.display='none'; Codehighlighter1_80_574_Closed_Image.style.display='inline'; Codehighlighter1_80_574_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_80_574_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_80_574_Closed_Text.style.display='none'; Codehighlighter1_80_574_Open_Image.style.display='inline'; Codehighlighter1_80_574_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span id="Codehighlighter1_80_574_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_80_574_Open_Text"><span style="color: #000000">{<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;pthread_mutex_t&nbsp;&nbsp;&nbsp;once_lock&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;PTHREAD_RECURSIVE_MUTEX_INITIALIZER;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">volatile</span><span style="color: #000000">&nbsp;pthread_once_t</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;ocptr&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;once_control;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;pthread_once_t&nbsp;tmp&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">ocptr;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;ANDROID_MEMBAR_FULL();<br /><img id="Codehighlighter1_306_558_Open_Image" onclick="this.style.display='none'; Codehighlighter1_306_558_Open_Text.style.display='none'; Codehighlighter1_306_558_Closed_Image.style.display='inline'; Codehighlighter1_306_558_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img id="Codehighlighter1_306_558_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_306_558_Closed_Text.style.display='none'; Codehighlighter1_306_558_Open_Image.style.display='inline'; Codehighlighter1_306_558_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(tmp&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;PTHREAD_ONCE_INIT)&nbsp;</span><span id="Codehighlighter1_306_558_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_306_558_Open_Text"><span style="color: #000000">{<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_mutex_lock(&nbsp;</span><span style="color: #000000">&amp;</span><span style="color: #000000">once_lock&nbsp;);<br /><img id="Codehighlighter1_391_508_Open_Image" onclick="this.style.display='none'; Codehighlighter1_391_508_Open_Text.style.display='none'; Codehighlighter1_391_508_Closed_Image.style.display='inline'; Codehighlighter1_391_508_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img id="Codehighlighter1_391_508_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_391_508_Closed_Text.style.display='none'; Codehighlighter1_391_508_Open_Image.style.display='inline'; Codehighlighter1_391_508_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(</span><span style="color: #000000">*</span><span style="color: #000000">ocptr&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;PTHREAD_ONCE_INIT)&nbsp;</span><span id="Codehighlighter1_391_508_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_391_508_Open_Text"><span style="color: #000000">{<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #000000">*</span><span style="color: #000000">init_routine)();<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ANDROID_MEMBAR_FULL();<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">ocptr&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">~</span><span style="color: #000000">PTHREAD_ONCE_INIT;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_mutex_unlock(&nbsp;</span><span style="color: #000000">&amp;</span><span style="color: #000000">once_lock&nbsp;);<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span></div>
<p>所以这个pthread_once_t必须是全局or静态变量<br />pthread_once最常用的case除了拿到TLS key外，init函数经常会使用这个，避免多线程同时调用。<br /><br />然后就是thread cancel<br />Android Bionic库没有实现 pthread_setcancelstate(int state, int* oldstate)以及pthread_cancel()<br />这里thread的取消，有些是取消不掉的，例如一些blocking call，所有的取消均是需要设定一些取消点的，<br /><br />有人有专门针对Android没有Thread Cancel来想办法<br />基本就是thread signal，在signal handler中去call pthread_exit();<br />or用PIPE在多路复用中break出来<br /><a href="http://blog.csdn.net/langresser/article/details/8531112">http://blog.csdn.net/langresser/article/details/8531112</a><br /><br />如果信号与硬件故障or计时器超时相关，那么信号会发送到引起事件的该线程中去，其他信号会发送到任意一个线程。<br />这里是说的POSIX线程模型，一般的信号都会发送给进程中没有阻塞该信号的某个线程。APUE讲的某个没有阻塞该信号的线程，其实有点模糊。<br /><br />但是Linux的实现不一样，linux的thread是clone出来的，就是共享资源的独立进程，这样子其实蛮自然的，也不容易复杂。<br />linux中，有可能线程就不会注意到该信号，这样讲也有点模糊，总之终端驱动程序的信号会将信号通知到进程组，这样子所有的thread就会都收到信号<br />如果你不想所有的线程都去关心信号，那么可以使用一个专门处理信号的线程<br />先将其他线程的signal都pthread_sigmask SIG_BLOCK掉，然后使用sigwait在特定的线程来等<br />pthread_sigmask和sigprocmask很像<br /><br />thread与fork<br />fork后的子进程会继承mutex, rw lock, condition的状态<br />但是子进程中只会存在一个线程，也就是那个调用fork的线程的副本，有个复杂的事情是关于上面继承下来的那些东西，子进程由于只有一个线程，没办法知道<br />上面那三个东西的具体状态，需要有个清理锁的动作 --&gt;pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))<br />我目前不知道这个东西的使用场景，而且不容易控制。<br />因为一般如果我们fork后都会接execu，这样地址空间就会改变，那么这些继承的东西就没用了。<br /><br />然后有谈一点关于线程IO的东西<br />pwrite/pread<br />也就是原子的进行lseek和r/w，但是这个并不能保证大家常见的冲突问题，也就是一个thread在写另外一个要读，所以这两个东西并不能解决同步的问题。<br /><br />作业:<br />12.3 理论上函数开始时屏蔽所有信号，函数结束时恢复，是可以做到异步信号安全的。如果你只是屏蔽一些信号，那么没办法做到，因为如果有其他信号进来，你call的函数里面有一些不可重入的函数，同样不能保证是异步安全的。<br /><br />12.5 fork可以在拿来执行可执行程序，现在应该就这一个Case。</p><img src ="http://www.cppblog.com/xieshuo/aggbug/200788.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-06-04 15:41 <a href="http://www.cppblog.com/xieshuo/archive/2013/06/04/200788.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LTZ看书之APUE9</title><link>http://www.cppblog.com/xieshuo/archive/2013/06/03/200775.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Mon, 03 Jun 2013 09:03:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/06/03/200775.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/200775.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/06/03/200775.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/200775.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/200775.html</trackback:ping><description><![CDATA[<p>线程函数<br />int pthread_equal(pthread_t tid1, pthread_t tid2)<br />pthread_t pthread_self(void)</p>
<p>int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr<br />&nbsp;&nbsp;&nbsp;&nbsp; void* (*start_rtn)(void), void* restrict arg)</p>
<p>thread被创建的时候会继承调用线程的浮点环境和信号屏蔽字，但是该线程的未决信号集将会被清楚，<br />清除未决信号集这件事情应该是没有疑问的，在thread创建之前pending住的信号，不应该deliver给下一个<br />Ps: 线程的浮点环境指的是啥? 看来以后我应该去注意下浮点数的运算原理。</p>
<p>pthread相关的函数会直接返回错误码，而不会和一些system call一样，置全局errno，两种方式都有好处，一个可以讲返回值<br />带回的错误代码集中起来，范围缩小；另外一个非常方便，关键点在于这一类共用errno的是否真的异常是可以共用的。</p>
<p>pthread_create返回之前有可能新的线程就已经开始run了</p>
<p>启动函数 void* (*start_rtn)(void)</p>
<p>可以通过return给回来，也可以通过pthread_exit给<br />这个会存在一个地方<br />通过pthread_join(tid, void**)取回来</p>
<p>这里join的和java join是一样的功能</p>
<p>如果这个东西是一个很大的东西:)，那么放到heap是最好的选择，不要放到stack上了，不然线程返回这东西就没了，join取到的内存地址就变成一个无效的了，SIGSEGV就会被发出来</p>
<p>pthread_cancel，同一个进程可以call，提出请求终止线程</p>
<p>pthread_cleanup_push<br />pthread_cleanup_pop</p>
<p>线程分离，这样子线程终止后可以释放一些资源，而不用一定要其他人来join<br />方法有两种，新建的时候加上分离属性<br />&nbsp;&nbsp;&nbsp; pthread_attr_init (&amp;attr);<br />&nbsp;&nbsp;&nbsp; pthread_attr_setdetachstate(&amp;attr, PTHREAD_CREATE_DETACHED);<br />&nbsp;&nbsp;&nbsp; ret = pthread_create(&amp;s_tid_dispatch, &amp;attr, eventLoop, NULL);</p>
<p>或者call pthread_detach(pthread_t tid)<br /></p>
<p>线程互斥与同步</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #000000">typedef&nbsp;</span><span style="color: #0000ff">struct</span><span style="color: #000000"><br /><img id="Codehighlighter1_15_41_Open_Image" onclick="this.style.display='none'; Codehighlighter1_15_41_Open_Text.style.display='none'; Codehighlighter1_15_41_Closed_Image.style.display='inline'; Codehighlighter1_15_41_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_15_41_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_15_41_Closed_Text.style.display='none'; Codehighlighter1_15_41_Open_Image.style.display='inline'; Codehighlighter1_15_41_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span id="Codehighlighter1_15_41_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_15_41_Open_Text"><span style="color: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">volatile</span><span style="color: #000000">&nbsp;value;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />}</span></span><span style="color: #000000">&nbsp;pthread_mutex_t;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top"  alt="" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top"  alt="" /></span></div>
<p>多注意volatile变量，这个东西理论上就是让编译器不要做优化，不要cache volatile类型的变量，<br />每次都去内存地址中拿，而不是寄存器/高速缓存副本，这种变量极容易被编译器不知道的人改变，例如其他线程。</p>
<p>静态初始化:<br />#define&nbsp; PTHREAD_MUTEX_INITIALIZER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {0}<br />#define&nbsp; PTHREAD_RECURSIVE_MUTEX_INITIALIZER&nbsp;&nbsp; {0x4000}<br />#define&nbsp; PTHREAD_ERRORCHECK_MUTEX_INITIALIZER&nbsp; {0x8000}<br />所谓的动态初始化<br />pthread_mutex_init; pthread_mutex_destroy</p>
<p>然后就是一些pthread mutex的基本处理函数了<br />lock,unlock<br />trylock;</p>
<p>这个trylock需要好好理解下，尝试获取lock，如果OK，那么lock他然后 return 0; 否则也不会suspend住，而是直接返回EBUSY</p>
<p>pthread_mutex_destroy, 会先去try lock，然后处理掉这个mutex的值。</p>
<p>这里稍微提一下</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;pthread_mutex_trylock(pthread_mutex_t&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">mutex)<br /><img id="Codehighlighter1_50_508_Open_Image" onclick="this.style.display='none'; Codehighlighter1_50_508_Open_Text.style.display='none'; Codehighlighter1_50_508_Closed_Image.style.display='inline'; Codehighlighter1_50_508_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_50_508_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_50_508_Closed_Text.style.display='none'; Codehighlighter1_50_508_Open_Image.style.display='inline'; Codehighlighter1_50_508_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span id="Codehighlighter1_50_508_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_50_508_Open_Text"><span style="color: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;mtype,&nbsp;tid,&nbsp;oldv,&nbsp;shared;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(__unlikely(mutex&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;NULL))<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;EINVAL;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;mtype&nbsp;&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(mutex</span><span style="color: #000000">-&gt;</span><span style="color: #000000">value&nbsp;</span><span style="color: #000000">&amp;</span><span style="color: #000000">&nbsp;MUTEX_TYPE_MASK);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;shared&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(mutex</span><span style="color: #000000">-&gt;</span><span style="color: #000000">value&nbsp;</span><span style="color: #000000">&amp;</span><span style="color: #000000">&nbsp;MUTEX_SHARED_MASK);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br /><img id="Codehighlighter1_247_276_Open_Image" onclick="this.style.display='none'; Codehighlighter1_247_276_Open_Text.style.display='none'; Codehighlighter1_247_276_Closed_Image.style.display='inline'; Codehighlighter1_247_276_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img id="Codehighlighter1_247_276_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_247_276_Closed_Text.style.display='none'; Codehighlighter1_247_276_Open_Image.style.display='inline'; Codehighlighter1_247_276_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_247_276_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff">/**/</span><span id="Codehighlighter1_247_276_Open_Text"><span style="color: #008000">/*</span><span style="color: #008000">&nbsp;Handle&nbsp;common&nbsp;case&nbsp;first&nbsp;</span><span style="color: #008000">*/</span></span><span style="color: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(&nbsp;__likely(mtype&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;MUTEX_TYPE_NORMAL)&nbsp;)<br /><img id="Codehighlighter1_330_498_Open_Image" onclick="this.style.display='none'; Codehighlighter1_330_498_Open_Text.style.display='none'; Codehighlighter1_330_498_Closed_Image.style.display='inline'; Codehighlighter1_330_498_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img id="Codehighlighter1_330_498_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_330_498_Closed_Text.style.display='none'; Codehighlighter1_330_498_Open_Image.style.display='inline'; Codehighlighter1_330_498_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_330_498_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_330_498_Open_Text"><span style="color: #000000">{<br /><img id="Codehighlighter1_402_469_Open_Image" onclick="this.style.display='none'; Codehighlighter1_402_469_Open_Text.style.display='none'; Codehighlighter1_402_469_Closed_Image.style.display='inline'; Codehighlighter1_402_469_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img id="Codehighlighter1_402_469_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_402_469_Closed_Text.style.display='none'; Codehighlighter1_402_469_Open_Image.style.display='inline'; Codehighlighter1_402_469_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(__atomic_cmpxchg(shared</span><span style="color: #000000">|</span><span style="color: #000000">0</span><span style="color: #000000">,&nbsp;shared</span><span style="color: #000000">|</span><span style="color: #000000">1</span><span style="color: #000000">,&nbsp;</span><span style="color: #000000">&amp;</span><span style="color: #000000">mutex</span><span style="color: #000000">-&gt;</span><span style="color: #000000">value)&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">)&nbsp;</span><span id="Codehighlighter1_402_469_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_402_469_Open_Text"><span style="color: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ANDROID_MEMBAR_FULL();<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;EBUSY;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /></span></div>
<p></span><br />__likely/__unlikely函数用来告诉编译器优化代码，类似if else中最有可能or最没有可能发生的Case</p>
<p>mutex就有deadlock的问题，单线程，如果有代码重入重复获取锁就会deadlock，因为你走不到你unlock的地方去；另外<br />常见的deadlock就是lock比较多，又没有设计好顺序，这个应该从业务逻辑上就应该定义好，当然有时候有的人用的时候or改代码的时候<br />并没有理清这些lock的关系，是否有dependency，比较难通过借用一些编译系统来Cover住，然后改完就有bug。<br /><br /></p>
<p>然后还有一种需要设计好的是锁的粒度<br />太粗太细都不好<br />粒度太粗，lock住的东西太多，很多线程都要等lock，最后这个东西会演变成一个串行的东西<br />粒度太细，lock又变的太多，不停的需要lock/unlock，performance就会变差。<br />目前看到的Android上的很多lock都太粗。<br /><br /></p>
<p>rw锁 -&gt;读写锁<br />基本理念就是读不会影响临界区发生变化<br />所以读模式的rw lock可以多个人占用，写模式的rw lock时能被一个线程lock</p>
<p>只要有写模式lock请求，那么后面的读模式lock请求一般实现是都会被Suspend住，不然因为读模式下，可以重复lock，如果不<br />suspend，那么写模式的lock请求有可能永远得不到相应。<br />rw锁一般用在 read比 write行为多的多的场景，允许多线程并发去读，单一线程去写。<br /><br /></p>
<p>然后会想到spinlock，可以去网上search看下基本概念，spinlock一般在SMP架构下会比较有效果。<br /><br /></p>
<p>mutex是一种同步机制or讲这是一种互斥机制 -&gt; Java synchronize<br />还一种就是条件变量 condition.. -&gt; wait/notify<br /><br /></p>
<p>这里有段话很好<br />条件变量给多个线程提供了一个回合的场所，条件变量与互斥量一起使用的时候，允许线程以无竞争方式等待特定的条件发生。<br /><br />作业:<br />1.线程之间传递数据不要用stack变量，用放到下面这些地方的变量就好，RW/RO/ZI/Heap就没事了<br />4.<br />现在一般都是这样</p>
<p>&nbsp;&nbsp;&nbsp; pthread_mutex_lock(&amp;s_startupMutex);</p>
<p>&nbsp;&nbsp;&nbsp; s_started = 1;<br />&nbsp;&nbsp;&nbsp; pthread_cond_broadcast(&amp;s_startupCond);</p>
<p>&nbsp;&nbsp;&nbsp; pthread_mutex_unlock(&amp;s_startupMutex);</p>
<p>会在broadcast后才unlock<br />否则有比较高的概率，unlock后，被其他线程将条件改掉，这个时候broadcast出去就没有意义了。<br />但是这种也有可能会被另外一个线程，并非wait在那里的线程改变条件值<br /><br />所以 pthread_cond_wait 返回并不意味着条件一定为真了<br />最好是always check条件<br />类似这种<br />&nbsp;&nbsp;&nbsp; while (s_started == 0) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pthread_cond_wait(&amp;s_startupCond, &amp;s_startupMutex);<br />&nbsp;&nbsp;&nbsp; }</p><img src ="http://www.cppblog.com/xieshuo/aggbug/200775.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-06-03 17:03 <a href="http://www.cppblog.com/xieshuo/archive/2013/06/03/200775.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LTZ做作业之APUE8</title><link>http://www.cppblog.com/xieshuo/archive/2013/06/02/200761.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Sun, 02 Jun 2013 13:52:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/06/02/200761.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/200761.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/06/02/200761.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/200761.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/200761.html</trackback:ping><description><![CDATA[<p>信号<br />提供异步时间处理方式<br />触发时机:<br />1.终端命令<br />2.硬件异常，由kernel抛向对应的Process<br />3.kill函数/kill命令(超级用户or Process的user相同，这里的user id一般是指实际用户ID or 有效用户ID，如果支持 _POSIX_SAVED_IDS,那么检查saved-user-id)<br />4.软件触发(满足信号条件)</p>
<p>这里也稍微解释下Kill这个东西，kill函数，kill命令并不是字面上杀掉某些东西，kill只是在特定的时间发送信号，<br />具体的处理取决于信号本身和信号的处理方式。</p>
<p>信号的处理方式:<br />这个有点类似Java Exception的处理方式，catch住or往上throw</p>
<p>APUE讲的信号处理方式有三种<br />1.忽略，SIGKILL/SIGSTOP不能忽略；一般如果Process自己不管的话，应该会走到系统默认的处理流程中，所以不能忽略这件事情是系统自己就会保证的。<br />2.捕捉信号，例如SIGCHLD,一般parent会call waitpid取子进程终止状态，避免他处理Zombie状态。<br />3.执行系统默认动作</p>
<p>我感觉1和3可以归为一类吧，只是有些signal没有系统默认动作，然后就跳过去了。一般的系统默认动作也就是终止进程。</p>
<p>SIGKILL/SIGSTOP不能被忽略的原因我觉得讲的不错，提供超级用户终止进程的可靠方法，不然后续有可能进程的行为是未定义的.</p>
<p>signal函数定义:(</p>
<p>void (*signal(int signo, void(*func)(int)))(int);</p>
<p>这个C函数的声明有点难看懂</p>
<p>APUE讲signal的语义与实现有关，所以建议大家都用sigaction</p>
<p>不过我看了下Android Bionic下的实现，分别包含BSD以及SYSV的版本，但也都变成了sigaction，所以一般在C库中就保证了这一点，也就无所谓了。</p>
<p>&nbsp;</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;__sighandler_t<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />_signal(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;&nbsp;signum,&nbsp;__sighandler_t&nbsp;&nbsp;handler,&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;&nbsp;flags)<br /><img id="Codehighlighter1_80_350_Open_Image" onclick="this.style.display='none'; Codehighlighter1_80_350_Open_Text.style.display='none'; Codehighlighter1_80_350_Closed_Image.style.display='inline'; Codehighlighter1_80_350_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_80_350_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_80_350_Closed_Text.style.display='none'; Codehighlighter1_80_350_Open_Image.style.display='inline'; Codehighlighter1_80_350_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span id="Codehighlighter1_80_350_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_80_350_Open_Text"><span style="color: #000000">{<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">struct</span><span style="color: #000000">&nbsp;sigaction&nbsp;&nbsp;sa;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;__sighandler_t&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;SIG_ERR;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;sigemptyset(&nbsp;</span><span style="color: #000000">&amp;</span><span style="color: #000000">sa.sa_mask&nbsp;);<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;sa.sa_handler&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;handler;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;sa.sa_flags&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;flags;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(&nbsp;</span><span style="color: #000000">!</span><span style="color: #000000">sigaction(&nbsp;signum,&nbsp;</span><span style="color: #000000">&amp;</span><span style="color: #000000">sa,&nbsp;</span><span style="color: #000000">&amp;</span><span style="color: #000000">sa&nbsp;)&nbsp;)<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(__sighandler_t)&nbsp;sa.sa_handler;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;result;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />__sighandler_t&nbsp;bsd_signal(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;signum,&nbsp;__sighandler_t&nbsp;handler)<br /><img id="Codehighlighter1_416_465_Open_Image" onclick="this.style.display='none'; Codehighlighter1_416_465_Open_Text.style.display='none'; Codehighlighter1_416_465_Closed_Image.style.display='inline'; Codehighlighter1_416_465_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_416_465_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_416_465_Closed_Text.style.display='none'; Codehighlighter1_416_465_Open_Image.style.display='inline'; Codehighlighter1_416_465_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span id="Codehighlighter1_416_465_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_416_465_Open_Text"><span style="color: #000000">{<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;_signal(signum,&nbsp;handler,&nbsp;SA_RESTART);<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />__sighandler_t&nbsp;sysv_signal(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;signum,&nbsp;__sighandler_t&nbsp;handler)<br /><img id="Codehighlighter1_531_582_Open_Image" onclick="this.style.display='none'; Codehighlighter1_531_582_Open_Text.style.display='none'; Codehighlighter1_531_582_Closed_Image.style.display='inline'; Codehighlighter1_531_582_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_531_582_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_531_582_Closed_Text.style.display='none'; Codehighlighter1_531_582_Open_Image.style.display='inline'; Codehighlighter1_531_582_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span id="Codehighlighter1_531_582_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_531_582_Open_Text"><span style="color: #000000">{<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;_signal(signum,&nbsp;handler,&nbsp;SA_RESETHAND);<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span></div>
<p><br />exec函数会讲信号处理方式还原为系统默认，这个应该毫无疑问，exec后地址空间就不一样了，保留之前的捕捉函数也是无意义的；在这之前是有意义的，我的意思是说fork后exec之前。</p>
<p>后面有列一大堆是否可以重入的函数，不太想记，然后讲到了malloc<br />我想不能重入的函数无外乎两种类型<br />one: 自己有maintain一些全局or static变量 --&gt; malloc 维护分配内存时static heap linklist<br />two: 函数参数里面有引用之类的，会影响调用者的情况。</p>
<p>然后我看到这个立马就想到了线程安全，malloc是线程安全的麽?<br />去看了下Bionic的实现，然后就又看到下面这个名字 Dong Lea，马上就会想到Java Concurrent库，看到这个你直接就会有想法，Bionic里面这个malloc肯定是线程安全的；<br />有时候被这些东西搞的很累，比较烦他，而且Bionic里面用的malloc的那个实现版本(aka dlmalloc)我又没看懂:(，只好去网上search了一下，有个人做过实验，有些结论还是可以参考的<br /><a href="http://www.360doc.com/content/12/0420/23/168576_205320609.shtml">http://www.360doc.com/content/12/0420/23/168576_205320609.shtml</a></p>
<p>总的来说，这个东西取决于C库实现，我想Bionic和Glibc都应该一样会支持两种不同的版本，然后编译的时候就可以确定是否有线程相关操作，然后在link的时候link过来不同的版本</p>
<p>线程安全和信号安全是两个概念</p>
<p>如果在线程安全的malloc中，信号处理函数中发生重入，那么应该是会发生dead lock<br />如果是非线程安全中，那么应该是所谓的 undefined behavior.</p>
<p>前面还有一个概率忘记写<br />早期的Unix系统，如果系统在执行一个低速系统调用(基本可以总结为blocking IO:包括IPC，File IO，ioctl)，那么如果捕捉到信号，那么系统就会中断这个system call --&gt;EINTR, 这在当时是有理由的，而且理由看起来也合理，但是由于user有时候并不知道某些系统调用是否是低速系统调用，BSD引进了自动重启的功能，linux follow这种规则</p>
<p>然后有几个版本的signal函数<br />signal默认自动重启<br />_signal(signum, handler, SA_RESTART) 这是由于在sigaction中的flag为SA_RESTART，上面sysV的实现我不想多写了。<br />sigaction也就是可选的了。</p>
<p>但一般我印象中好多 read/write都是会自己判断返回值以及errno 是否为 EINTR，然后retry，因为上面这种方式依赖系统实现，需要将所有的signal都设定为SA_RESTART，那么如果有某个信号发生的时候，被他INTR的系统调用才会自动重启，不知道默认signal在注册处理行为的时候是不是如此，感觉不太好用。</p>
<p>alarm函数<br />对于很多像alarm这种函数，在设计时or使用时均应该考虑临界值的问题<br />alarm的唯一性，是by process的，process单例<br />所以如果alarm两次，那么第一次会被覆盖，怎么处理第一次未完成的情况-&gt;返回值会带回来剩余的时间<br />怎么取消设定的alarm<br />传入值为0 means cancel<br />总之了，这个东西设计的时候还蛮完善的<br /><br />后面还有一堆有关signal的标准函数，这里也就不一一列举<br /><br />作业:<br />1.去掉for(;;), 那捕捉到SIGUSR1就返回了，pause()只要捕捉到信号，等信号处理完时自己就会返回并带回EINTR。不晓得为啥有这种题目...<br />2.实现sig2str，这有点无聊了.:(不写<br />3.画runtime stack的样子。<br />4.IO操作的超时最好不要采用alarm的方式，各种原子问题，select/poll是最好的选择。<br />后面有好一些是要写代码的...<br />我略想，然后就不太愿意写了.<br />PS:有些东西略难...我也是有点想不清楚的样子，打算慢慢搞。<br /><br />后面决定把标题改一下，顺利看完书吧...Orz.</p><img src ="http://www.cppblog.com/xieshuo/aggbug/200761.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-06-02 21:52 <a href="http://www.cppblog.com/xieshuo/archive/2013/06/02/200761.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LTZ做作业之APUE7</title><link>http://www.cppblog.com/xieshuo/archive/2013/05/31/200728.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Fri, 31 May 2013 11:50:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/05/31/200728.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/200728.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/05/31/200728.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/200728.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/200728.html</trackback:ping><description><![CDATA[<div><font style="background-color: #cbe9cf"><span style="background-color: #ffffff">第九章 进程关系</span><br /><span style="background-color: #ffffff">也是首先记录基本概念</span><br /><br /><span style="background-color: #ffffff">关于linux终端的概念，这个最好仔细想一下，因为之后会有伪终端的内容，如果不想的具体一些，那么会比较难有感觉。下面有个链接，我觉得写的还可以。</span><br /><a href="http://blog.csdn.net/smstong/article/details/8760331"><span style="background-color: #ffffff">http://blog.csdn.net/smstong/article/details/8760331</span></a><br /><br /><span style="background-color: #ffffff">我写下我的理解，肯定有不太对的地方，但只能到此。</span><br /><br /><span style="background-color: #ffffff">广义的讲: 终端就是用来和User交互的设备，键盘，显示器，打印机...</span><br /><span style="background-color: #ffffff">这里一般讲的是狭义的终端:</span><br /><span style="background-color: #ffffff">一般有两种: 字符哑终端; 图形终端</span><br /><span style="background-color: #ffffff">字符哑终端，就是自己没有处理能力，只能输入输出的;</span><br /><span style="background-color: #ffffff">图形终端其实他有处理能力，例如framebuffer...</span><br /><span style="background-color: #ffffff">linux中，真正能称得上是终端的其实物理组件就是键盘+显示器，或者称这两个东西叫做控制台</span><br /><span style="background-color: #ffffff">但是linux虚拟出来了6个终端设备</span><br /><span style="background-color: #ffffff">tty1 ~ tty6</span><br /><span style="background-color: #ffffff">而/dev/tty0是一个symbol link指向当前终端，/dev/console则可以为/dev/tty0提供缓冲（这个我不确定）</span><br /><br /><span style="background-color: #ffffff">tty7是图形终端</span><br /><span style="background-color: #ffffff">图形终端中，会用软件类似rxvt虚拟出更多的伪终端，类似我们看到的/dev/pts/0...</span><br /><br /><span style="background-color: #ffffff">伪终端是一种虚拟终端</span><br /><span style="background-color: #ffffff">但是有时候所谓的虚拟终端还是能对应上物理设备</span><br /><br /><span style="background-color: #ffffff">对于伪终端pts和ptm</span><br /><span style="background-color: #ffffff">我自己感觉就像PIPE，只不过输入输出时有终端行规程来控制格式。</span><br /><br /><span style="background-color: #ffffff">后面有讲会话，会话由进程组构成，不过我想不清楚运用场景...</span><br /><br /><span style="background-color: #ffffff">这一章有一些没看懂，进程组，会话，控制终端...因为不怎么用，先放这里，以后再翻。</span></font></div>
<div><font style="background-color: #cbe9cf"><span style="background-color: #ffffff">没有作业...</span><br /></div></font><img src ="http://www.cppblog.com/xieshuo/aggbug/200728.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-05-31 19:50 <a href="http://www.cppblog.com/xieshuo/archive/2013/05/31/200728.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LTZ做作业之APUE6</title><link>http://www.cppblog.com/xieshuo/archive/2013/05/31/200687.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Thu, 30 May 2013 16:25:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/05/31/200687.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/200687.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/05/31/200687.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/200687.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/200687.html</trackback:ping><description><![CDATA[<div>记录一些基本概念</div>
<div>PID == 0的是Swapper进程(调度进程)，这个Process的RO应该是pre load的时候都放到内存里面了，不run任何磁盘上的code，属于系统进程。</div>
<div>PID == 1的是init进程。这个是一个以root运行的用户进程</div>
<div></div>
<div>fork，我有看到一个词fork hope...我觉得不错，我也希望我能fork出hope...</div>
<div></div>
<div>fork的返回状态是有原因的，APUE的解释还不错吧</div>
<div>fork 在 父进程中返回子进程的 PID，因为没有任何API能知道 child process id，而且child可能会有很多。。。</div>
<div>fork 在 子进程中返回0，是因为0是swapper进程，所以没关系；也没必要返回父进程ID，可以通过getppid()得到。</div>
<div></div>
<div>fork后，子进程父进程共享正文 RO</div>
<div>RW ZI Heap Stack是父进程的副本，副本意味着copy</div>
<div></div>
<div>linux已经有很多使用COW了(copy-on-write)，这个东西应该是要借助MMU</div>
<div>因为基本fork后会跟exec，那样子所有的东西又都需要马上被替换掉</div>
<div></div>
<div>都设置为Read Only，无论是parent还是child只要一个试图修改，那么就copy，单位应该是MMU的Page</div>
<div></div>
<div>linux有提供clone，这个东西可以由调用者控制什么东西是要和父进程共享的，我还没看到pthread的实现，猜想应该就是通过这东西实现资源共享的。</div>
<div></div>
<div>tips:{</div>
<div>对于字符串求长度，sizeof会计算null，这也正常，因为sizeof()是算memory被分配的大小；strlen计算的是有效字符的长度，不包含null。</div>
<div>如果字符串是常量，sizeof能在编译时被优化，也变成常量，strlen则是函数调用不能被优化。</div>
<div>}</div>
<div></div>
<div>vfork</div>
<div>具体实现我没有具体去想，这个东西也没有什么特别的，跟fork不一样的是，他必须接上exec or exit，否则会run在父进程空间而不做任何复制</div>
<div>所以会有同步，在子进程还未call exec or exit前，父进程会被suspend。要不然父进程受的影响便是未知的。</div>
<div>另外这里也有讨论exit函数在做清理工作时对流的处理</div>
<div>应该是说 一般exit不会去做关闭流的动作，而把这件事情留给kernel，只是flush stream就好，否则类似遇到vfork这种会在父进程空间做事情的，</div>
<div>如果call exit把流给关闭了，会有一些不预期的结果。</div>
<div></div>
<div>父进程提前终止，那么子进程的父进程都会被置为1--&gt; init process.</div>
<div>init process会为每个子进程无论是自己fork出来的还是因为父进程提前终止而领养的做wait获取终止状态，避免zombie进程</div>
<div>处理方式应该是收到SIGCHLD后call wait(null)</div>
<div></div>
<div>wait系列的函数还蛮多的...</div>
<div>对于不想使自己的子进程处于zombie状态的，自己有还想做一些事情的且不想关心子进程结束状态的可以fork两次，exit第一次出来的进程，wait他，然后第二次fork出来的</div>
<div>进程的父进程就变成init了，不过需要使用这种技巧的Case我没想到。。。<br /><br />关于exec系列函数，我想最好还是记住，因为经常会用，不能每次用都去查吧。<br />一共6个，exec能给的最多就这三个参数，要run的程序路径；要给run的程序的参数；要给run的程序的环境变量<br />其中只有execve是 system call，其他都是库函数。<br />execve(const char* name, char* const argv[], char* const envp[])<br /><br />这里又有讲三个用户ID的用法<br />实际用户ID；有效用户ID；保存的设置用户ID<br /><br />这里有讲一个Case，应该算经典Case，也只有类似Case才能让你明白保存的设置用户ID的用途<br /><br />man程序为设置用户ID/设置组ID，就会在两种权限中切换。<br />运行man的时候 <br />real user id == login id<br />effective user id == man<br />saved effective user id == man<br /><br />在man访问完他自己拥有的那些file后，想运行一些命令call setuid(getuid())因为我们不是root<br />real user id == login id<br />effective user id == login id<br />saved effective user id == man</div>
<div>这个时候运行命令就是我们login时候的user的权限<br /><br />完了后面想设置回去的时候再call setuid(euid),这里euid就是man，之前可以保存在man自己的Context中<br />这个时候euid == saved effective user id，所以effective user id又被设置为man，这种情况下如果没有saved effective user id那用户权限就回不去了。<br />real user id == login id<br />effective user id == man<br />saved effective user id == man<br /><br />所以注意setuid 如果是root用户，那么三个ID都会被设置成目标ID，如果不是<br />则effective user id可能会改变 当目标ID为 real user id or saved effective user id的时候，从设计的角度仔细想，这样子也合理。<br /><br />system的实现<br />execel shell，而不是直接去fork/execel本身要system的程序，那样会变得异常复杂，你需要解析cmdString，分离出程序和参数，带入和shell一样的环境变量，找到目的程序，execute他，然后带回结果。<br />一般会去call system的程序不要使用set-user-id，这样容易导致安全泄露。容易让system出来的那个process权限扩大，不易控制。<br /><br />贴一个system的实现，非常nice 
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /><span style="color: #000000">#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">sys</span><span style="color: #000000">/</span><span style="color: #000000">types.h</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">signal.h</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">stdlib.h</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">unistd.h</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">paths.h</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">sys</span><span style="color: #000000">/</span><span style="color: #000000">wait.h</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">extern</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">**</span><span style="color: #000000">environ;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">int</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />system(</span><span style="color: #0000ff">const</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">command)<br /><img id="Codehighlighter1_181_990_Open_Image" onclick="this.style.display='none'; Codehighlighter1_181_990_Open_Text.style.display='none'; Codehighlighter1_181_990_Closed_Image.style.display='inline'; Codehighlighter1_181_990_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_181_990_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_181_990_Closed_Text.style.display='none'; Codehighlighter1_181_990_Open_Image.style.display='inline'; Codehighlighter1_181_990_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_181_990_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_181_990_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;pid_t&nbsp;pid;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;sig_t&nbsp;intsave,&nbsp;quitsave;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;sigset_t&nbsp;mask,&nbsp;omask;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;pstat;<br /><img id="Codehighlighter1_273_296_Open_Image" onclick="this.style.display='none'; Codehighlighter1_273_296_Open_Text.style.display='none'; Codehighlighter1_273_296_Closed_Image.style.display='inline'; Codehighlighter1_273_296_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_273_296_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_273_296_Closed_Text.style.display='none'; Codehighlighter1_273_296_Open_Image.style.display='inline'; Codehighlighter1_273_296_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">argp[]&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_273_296_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_273_296_Open_Text"><span style="color: #000000">{</span><span style="color: #000000">"</span><span style="color: #000000">sh</span><span style="color: #000000">"</span><span style="color: #000000">,&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">-c</span><span style="color: #000000">"</span><span style="color: #000000">,&nbsp;NULL,&nbsp;NULL}</span></span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" /><br /><img id="Codehighlighter1_316_337_Open_Image" onclick="this.style.display='none'; Codehighlighter1_316_337_Open_Text.style.display='none'; Codehighlighter1_316_337_Closed_Image.style.display='inline'; Codehighlighter1_316_337_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_316_337_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_316_337_Closed_Text.style.display='none'; Codehighlighter1_316_337_Open_Image.style.display='inline'; Codehighlighter1_316_337_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(</span><span style="color: #000000">!</span><span style="color: #000000">command)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_316_337_Closed_Text">/**/</span><span id="Codehighlighter1_316_337_Open_Text"><span style="color: #008000">/*</span><span style="color: #008000">&nbsp;just&nbsp;checking<img alt="" src="http://www.cppblog.com/Images/dot.gif" />&nbsp;</span><span style="color: #008000">*/</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">(</span><span style="color: #000000">1</span><span style="color: #000000">);<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;argp[</span><span style="color: #000000">2</span><span style="color: #000000">]&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">)command;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;sigemptyset(</span><span style="color: #000000">&amp;</span><span style="color: #000000">mask);<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;sigaddset(</span><span style="color: #000000">&amp;</span><span style="color: #000000">mask,&nbsp;SIGCHLD);<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;sigprocmask(SIG_BLOCK,&nbsp;</span><span style="color: #000000">&amp;</span><span style="color: #000000">mask,&nbsp;</span><span style="color: #000000">&amp;</span><span style="color: #000000">omask);<br /><img id="Codehighlighter1_495_700_Open_Image" onclick="this.style.display='none'; Codehighlighter1_495_700_Open_Text.style.display='none'; Codehighlighter1_495_700_Closed_Image.style.display='inline'; Codehighlighter1_495_700_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_495_700_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_495_700_Closed_Text.style.display='none'; Codehighlighter1_495_700_Open_Image.style.display='inline'; Codehighlighter1_495_700_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">switch</span><span style="color: #000000">&nbsp;(pid&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;vfork())&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_495_700_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_495_700_Open_Text"><span style="color: #000000">{<br /><img id="Codehighlighter1_509_519_Open_Image" onclick="this.style.display='none'; Codehighlighter1_509_519_Open_Text.style.display='none'; Codehighlighter1_509_519_Closed_Image.style.display='inline'; Codehighlighter1_509_519_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_509_519_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_509_519_Closed_Text.style.display='none'; Codehighlighter1_509_519_Open_Image.style.display='inline'; Codehighlighter1_509_519_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">case</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">1</span><span style="color: #000000">:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_509_519_Closed_Text">/**/</span><span id="Codehighlighter1_509_519_Open_Text"><span style="color: #008000">/*</span><span style="color: #008000">&nbsp;error&nbsp;</span><span style="color: #008000">*/</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sigprocmask(SIG_SETMASK,&nbsp;</span><span style="color: #000000">&amp;</span><span style="color: #000000">omask,&nbsp;NULL);<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">(</span><span style="color: #000000">-</span><span style="color: #000000">1</span><span style="color: #000000">);<br /><img id="Codehighlighter1_589_599_Open_Image" onclick="this.style.display='none'; Codehighlighter1_589_599_Open_Text.style.display='none'; Codehighlighter1_589_599_Closed_Image.style.display='inline'; Codehighlighter1_589_599_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_589_599_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_589_599_Closed_Text.style.display='none'; Codehighlighter1_589_599_Open_Image.style.display='inline'; Codehighlighter1_589_599_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">case</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_589_599_Closed_Text">/**/</span><span id="Codehighlighter1_589_599_Open_Text"><span style="color: #008000">/*</span><span style="color: #008000">&nbsp;child&nbsp;</span><span style="color: #008000">*/</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sigprocmask(SIG_SETMASK,&nbsp;</span><span style="color: #000000">&amp;</span><span style="color: #000000">omask,&nbsp;NULL);<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;execve(_PATH_BSHELL,&nbsp;argp,&nbsp;environ);<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;_exit(</span><span style="color: #000000">127</span><span style="color: #000000">);<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" />&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;intsave&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(sig_t)&nbsp;&nbsp;bsd_signal(SIGINT,&nbsp;SIG_IGN);<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;quitsave&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(sig_t)&nbsp;bsd_signal(SIGQUIT,&nbsp;SIG_IGN);<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;pid&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;waitpid(pid,&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">)</span><span style="color: #000000">&amp;</span><span style="color: #000000">pstat,&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">);<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;sigprocmask(SIG_SETMASK,&nbsp;</span><span style="color: #000000">&amp;</span><span style="color: #000000">omask,&nbsp;NULL);<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff">void</span><span style="color: #000000">)bsd_signal(SIGINT,&nbsp;intsave);<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff">void</span><span style="color: #000000">)bsd_signal(SIGQUIT,&nbsp;quitsave);<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;(pid&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">1</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">?</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">1</span><span style="color: #000000">&nbsp;:&nbsp;pstat);<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" />}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span></div>这里使用了vfork和execve，他的实现细节以及可移植性做的还是蛮完美的。<br /><br />作业：<br />8.1 如果并非如此那么exit就没有关闭stdout，这在之前也讲过一般的C库都不会这么多此一举，一般他们只会去flush stream不会close<br />所以如果想达到那种效果，可以自己去显示去fclose<br /><br />8.2 <br />这个有点复杂啦，vfork后理论上应该立即调用exec才对，如果不去exec or exit，那么子进程就run在父进程的数据空间，如果子进程从另外一个函数返回，不call exit，那么就会一直等到main函数退出，父进程才会执行，但是这个时候stack里面已经没有任何东西了，我不确定会发生什么事情<br /><br />8.5<br />不提供返回保存的有效用户ID的函数<br /><br />8.6 8.7稍后贴上source code.<br /><br /><br /></div><img src ="http://www.cppblog.com/xieshuo/aggbug/200687.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-05-31 00:25 <a href="http://www.cppblog.com/xieshuo/archive/2013/05/31/200687.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LTZ做作业之APUE5</title><link>http://www.cppblog.com/xieshuo/archive/2013/05/28/200655.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Tue, 28 May 2013 12:00:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/05/28/200655.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/200655.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/05/28/200655.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/200655.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/200655.html</trackback:ping><description><![CDATA[第六章不看，直接到第七章<br /><br />所谓的启动例程用C写起来一般是这样，但一般情况这个会是汇编来写<br />exit(main(argc, argv))<br /><br />exit函数<br />_exit和_Exit立即进入kernel，exit则需要做完必要的清理工作，先run注册过的终止处理程序，然后清理没有关闭的流。<br />exit _Exit是ISO C标准，_exit则是Posix，所以头文件不一样<br />前面是stdlib.h 后面是unistd.h <br /><br />关于malloc，calloc，realloc<br />malloc分配的空间初始值不确定；calloc会帮忙清零；realloc可以动态分配合适的大小空间，如果不够会有copy原始数据的动作，所以对realloc之前的memory记录指针不是好方法，因为realloc完就可能失效。<br /><br />这三个都是去call sbrk来扩大缩小heap<br />但一般只是扩大，在free的时候 malloc 会把扩大的 memory cache起来(virual memory)<br /><br />setjmp, longjmp<br />跳转函数，支持跨越函数帧的跳转，goto是函数内跳转<br />注意: longjmp到setjmp的点后，一般情况 全局/局部/局部静态变量都没办法恢复到setjmp时的值；register/volatile变量在编译后(cc -O)会放到寄存器中，这些都能实现回滚。这也就说明setjmp的时候，jmp_buf并没有保存这些值。<br /><br />7.1 如果不调用return 和 exit 函数返回值用了printf的返回值，Orz...我没想清楚怎么做的。<br /><br />7.2 取决于printf面对的设备类型，行缓冲的话，碰到换行就会被输出，如果是全缓冲，那么则要么需要call fflush，要么等stream被close。<br /><br />7.3 不用参数传递，不用全局变量，Orz...要传递argc, argv --&gt;NO<br /><br />7.4 通常null就是0，一般指针为 null 的时候意味着空指针引用，一般0都不会去放数据，RO的起始位置在一个更高的地址，0会是无效的，用来指引程序出错。<br /><br />7.5<br />typedef void func(void);<br />int atexit(func* fp);<br />或者<br />typedef void (*func)(void);<br />int atexit(func fp);<br />我喜欢下面那种，因为函数本身就是个pointer。<br /><br />7.6 calloc会将分配的空间清零，ISO C不保证0值和空指针相等<br /><br />7.7 size输出的是静态的RO，RW，ZI，像Heap，Stack是runtime才有的。<br /><br />7.8 理论上不带debug信息的.out文件应该大小都是等于RO+RW+ZI的。<br /><br />7.9 这就是.a和.so的区别了，link的时候静态库会被直接copy过来，所以会变大很多。<br /><br />7.10 变量作用域的故事。<img src ="http://www.cppblog.com/xieshuo/aggbug/200655.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-05-28 20:00 <a href="http://www.cppblog.com/xieshuo/archive/2013/05/28/200655.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LTZ做作业之APUE4</title><link>http://www.cppblog.com/xieshuo/archive/2013/05/28/200624.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Tue, 28 May 2013 11:24:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/05/28/200624.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/200624.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/05/28/200624.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/200624.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/200624.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 这一章会让你想起一些尘封的记忆上大学的时候，教C语言的老师会教大家文件IO，那个时候讲的都是标准输入输出，都是C库的实现，和第三章Unbuffered IO要区别开来，目的之前讲过减少System Call的调用次数，提高PerformanceJava上也有类似的实现，只不过Java的实现会更加Common一些，类似BufferedInputStream/BufferedOutputStream，...&nbsp;&nbsp;<a href='http://www.cppblog.com/xieshuo/archive/2013/05/28/200624.html'>阅读全文</a><img src ="http://www.cppblog.com/xieshuo/aggbug/200624.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-05-28 19:24 <a href="http://www.cppblog.com/xieshuo/archive/2013/05/28/200624.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LTZ做作业之APUE3</title><link>http://www.cppblog.com/xieshuo/archive/2013/05/27/200611.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Mon, 27 May 2013 08:42:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/05/27/200611.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/200611.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/05/27/200611.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/200611.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/200611.html</trackback:ping><description><![CDATA[<p>这里要稍微写一些linux下复杂的权限管理，应该只是一小部分知识，还有一些关于cap的东西以后再看。</p>
<p>与process关联的ID<br />谁execute这个process的人称为real user id，应该就是登陆时使用的user<br />real group id也一样.<br />一般在一个登陆Session中，这两个值都不会改变，但是超级用户进程可以改变<br />像Android中每个APK有独自的User id，然后类似rild之类的native deamon process就会尝试改变自己的user id为类似radio之类的东西。</p>
<p>在运行中检查权限所使用的id称为有效用户id，effective user id<br />然后还有有效组ID<br />附加组ID</p>
<p>一般有效用户ID == 真实用户ID， 有效组ID == 真实组ID<br />但是如果在可执行文件的st_mode中有设置 set-user-ID/set-group-ID<br />那在执行这个文件的时候 有效用户ID和有效组ID会变成文件的owner</p>
<p>一般有设置set-user-ID/set-group-ID的程序都会获得额外的权限</p>
<p>关于文件权限，有一些容易引起误解的，也还有一些我自己也没有理解清楚的</p>
<p>文件权限比较好理解，O_TRUNC需要文件具有写权限。<br /><br />文件夹的写权限，应该就是类似能不能在其中create/update/delete文件和文件夹<br />文件夹的读权限，应该就是读文件夹里面的文件/文件夹列表，通常我们 ls 当前文件夹就必须具有读权限<br />文件夹的执行权限，这个东西听说又叫搜索位，通常我们cd XXX，就必须在当前文件夹下搜索XXX是否存在，然后就是当我们访问类似这种很长路径的文件/aaa/bbb/ccc/dd.txt<br />对aaa，bbb，ccc必须具有执行权限，就是搜索</p>
<p>一般如果具有读权限就应该就可以搜索，如果这之前有区别，就是应该是搜索的范围大于能读到的内容。<br />也就是之后需要知道一个Folder本身里面有写什么内容，我目前知道的是一定有当前的文件列表--&gt; TODO: 看情景分析 or 去看下 ls 的实现，ls里面有比较多参数有些是需要x的有些是需要r的，例如 ls -l如果没有执行权限就只能拿到 name ,能知道是folder还是file，除此之外其他的东西都拿不到，文件本身的权限，user，group<br /><br /><span style="background-color: yellow">--&gt;linux目录中记录的应该是只有两个东西 inode&nbsp;&amp; name.这与文件系统的实现有关。</span><br /><br />另外增删文件都需要WX权限<br /><br />另外内核对文件操作权限的判断顺序...如果是owner就会看owner权限，group权限就不会看了，如果在group中则others也就不看了，这个逻辑上正常，而且可以想一下kernel的实现，一定是if-else的判断出结果后直接返回。</p>
<p><br />这里就要提如果新建文件/文件夹的时候文件夹的owner user id和group id是谁<br /><font style="background-color: #cbe9cf">user id会是process 有效用户ID<br />group id可以有两种选择父folder的group id；or process有效组ID<br />linux中根据文件系统的不同有的可以在mount fs的时候选择<br /><br /><span style="background-color: #ffffff">文件长度: st_size</span><br /><span style="background-color: #ffffff">lseek到文件末尾之后的空间，会照成文件空洞</span><br /><span style="background-color: #ffffff">文件长度会+空洞的大小，但是这些空洞未必会占用磁盘空间。</span><br /><span style="background-color: #ffffff">du 命令可以看磁盘空间大小</span><br /><br /><span style="background-color: #ffffff">符号链接和所谓的硬链接完全是两回事，建议细读4.14，不要去上网search类似我这种自己记录给自己看的blog...:(</span><br /><br /><span style="background-color: #ffffff">这章内容比较多而且杂，主要是stat中的每个参数的意义，需要思考想清楚的东西也比较多，有比较多关于文件操作的System Call</span><br /><br /><span style="background-color: #ffffff">作业开始:</span><br /><span style="background-color: #ffffff">之后只写有点意义的题目，无意义的也没什么可以写的pass</span><br /><span style="background-color: #ffffff">4.1 stat和lstat的区别，stat基本不会关心是否是S_IFLNK(符号链接)，应该是看到S_IFLNK会往下去找真正的File，然后拿到属性值</span><br /><span style="background-color: #ffffff">而lstat旁道S_IFLNK则会直接返回。第一次看到这样的函数设计怪怪的，我的初始感觉是反的。我觉得stat是一个common的设计，不会针对不同的File类型来做一些区别。Orz...最后不是。</span><br /><br /><span style="background-color: #ffffff">4.2 umask 777意味着rwxrwxrwx全部变没掉，但是这也没关系，不知道出题人的意思</span><br /><br /><span style="background-color: #ffffff">4.5 目录和符号链接的长度不可能为0，目录创建出来就会包含. 和 ..而且 . 的inode指向自己本身会占磁盘空间，符号链接肯定也是不能为0的，其中有存指向的链接path</span><br /><br /><span style="background-color: #ffffff">4.6 这个有点意思，后面贴代码</span><br /><br /><span style="background-color: #ffffff">4.7 这个看了下答案，没看懂&gt;为什么kernel默认的创建文件赋予的权限&#8220;可能会，也可能不会&#8221;受unmask的值的影响?</span><br /><br /><span style="background-color: #ffffff">4.8 du df的区别...</span><br /><br /><span style="background-color: #ffffff">4.9 ~ 后面的题大概看了下，不想写了，好多细节...</span><br /><br /></font></p>
<p>&nbsp;</p>
<p><br />&nbsp;</p><img src ="http://www.cppblog.com/xieshuo/aggbug/200611.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-05-27 16:42 <a href="http://www.cppblog.com/xieshuo/archive/2013/05/27/200611.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LTZ做作业之APUE2</title><link>http://www.cppblog.com/xieshuo/archive/2013/05/22/200521.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Wed, 22 May 2013 14:58:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/05/22/200521.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/200521.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/05/22/200521.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/200521.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/200521.html</trackback:ping><description><![CDATA[看了下第一次作业，那个排版和高亮背景有点瞎，这次能好点就不错了.<br /><br />第二章是关于POSIX以及XSI的一些标准和limitation，就不做作业了，直接到第三章，没有睡午觉，有些困，不要写错...<br /><br />先贴一些比较好的思路<br /><span style="color: red; background-color: yellow">(1)</span><br />在AF_LOCAL(Posix: AF_UNIX)的Socket编程中，对Client端来说需要connect<br />int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen)<br />这里需要给serv_addr一个length，这个length是一个真实的地址长度。<br />当socket为AF_UNIX的Socket时 socket address为sockaddr_un里面存放着地址类型以及socket path，我们需要知道sockaddr_un中真正存放数据的长度。<br /><br />函数offsetof是不错的选择<br />这个function的实现看起来可以学习，我先抄一段贴下面<br />
<p><strong>#define offsetof(TYPE, MEMBER) ((size_t) &amp; ((TYPE *)0)-&gt;MEMBER )</strong></p>
<p><strong>宏功能：获得一个结构体变量成员在此结构体中的偏移量。</strong></p>
<p>1. ( (TYPE *)0 ) 将零转型为TYPE类型指针; <br />2. ((TYPE *)0)-&gt;MEMBER 访问结构中的数据成员;</p>
<p>3. &amp;( ( (TYPE *)0 )-&gt;MEMBER )取出数据成员的地址，即相对于0的偏移量，要的就这个; <br />4.(size_t)(&amp;(((TYPE*)0)-&gt;MEMBER))结果转换类型，size_t应该最终为unsigned int类型。 <br />此宏的巧妙之处在于将 0 转换成(TYPE*)，这样结构体中成员的地址即为在此结构体中的偏移量。<br /><br />这里主要还是利用了 '-&gt;' 这个符号的功能，编译器解析这个符号的时候应该就是通过偏移量取值，所以这里先定义好取值规则(TYPE*)然后利用偏移量取值反向再取地址，再然后因为起始地址是0，取回的地址就变成了真正的偏移量。<br />还有一个知道member求整体的Ptr的Marco应该也蛮好用，括号比较多，我没头去看具体实现了...</p>
<p>&nbsp;</p>
<p><strong>#define container_of(ptr, type, member) ({ \ <br />const typeof( ((type *)0)-&gt;member ) *__mptr = (ptr); \ <br />(type *)( (char *)__mptr &#8211; offsetof(type,member) );})</strong></p>
<p><strong>宏功能：</strong>从结构体（<strong>type</strong>）某成员变量（<strong>member</strong>）指针（<strong>ptr</strong>）来求出该结构体（<strong>type</strong>）的首指针。<br /><br /><span style="background-color: yellow">(2)</span><br />有讨论一些东西，没有搞清楚，贴在这里以后有心力了再看，在看Rild，然后pthread在做线程同步的时候需要先lock，也许大家都是这样做，也一直这样做，但是突然就想到之前Java的时候讨论过的东西为什么wait/notify 一定要在一个synchronize block中，当然你可以讲，如果不会有exception抛出，你也还可以讲wait本来就会先释放lock然后把当前的thread放到Object waiting thread pool中然后挂起当前线程，实现就是这样子，但是从设计来讲，原因我没有想的特别清楚，如果不去lock，是不是因为wait/notify本身有很多操作没办法做multi thread...<br /><br />然后就是关于select的一些辅助的Marco，类似FD_SET，FD_ZERO之类的，简单讲就是一个long数组，每个元素的每个bit代表一个fd，然后做set，clear之类的动作，最大不能超过那个1024<br /><br />今天先到这里，写个序，明天正文...Orz<br /><br /><span style="background-color: yellow">(3)</span><br />继续讨论东西<br />有人为了在C++中作出类似Java可以自动释放内存的东西，也就是所谓的智能指针，Android有帮忙实现strong pointer/weak pointer，他的大概意思就是用一个第三者来看住当前new出来的object，采用的方式一般是引用计数，这种方式也许在Design Pattern中有专门的名字。一般利用编译器对这个第三者做自动释放的时候去检查计数器，看是否能释放他看管的object，C++里面编译器会自动去call ~Constructor就例如局部变量。<br /><br />有一些复杂的Case，就算是交叉引用了，Strong Pointer/Weak Pointer就是为了解决交叉引用的问题，从语义上讲父Object引用子Object，用SP，反过来用WP<br />只要SP为0，就可以释放Memory<br /><br />今天大家有讲Java的WeakReference，SoftReference，我就含糊了，我以为这东西和上面一样。<br />Java的WeakReference，SoftReference跟上面讲的完全不一样，由于没分清楚，混淆了。JVM就会处理引用交叉的问题，JVM处理引用交叉可以使用类似有向图，如果呈环状而且环中的任意点都没办法到GC Roots(VM stack中的Reference/static reference/JNI reference)，那么就都GC掉应该也没问题。<br />所以Java中的所谓的WeakReference/SoftReference跟SP/WP不一样，Java中普通赋值的reference都是强可及的Strong Reference。<br />WeakReference只是用来关心下那些将要被回收却没有回收的Object，一旦被GC Thread扫到就会被释放。<br />而SoftReference是JVM对Object的Cache，只要内存足够不会被释放。<br /><br />贴一个讲Android SP/WP的链接，之前有印象看过。<br /><a href="http://blog.csdn.net/luoshengyang/article/details/6786239">http://blog.csdn.net/luoshengyang/article/details/6786239</a><br /></p>
<p><br /><span style="background-color: yellow">(4)</span><br />Keep Thinking...<br />某人让我写一个处理字符串的函数，30min，&nbsp;我怎么也不能让他失望的，是吧~无论11点多的时候我头有多晕，我很开心的在那里写，很直白的讲，我自己用的本是个游戏机，没啥好环境。用C写了个，然后跑出来的结果出乎预料，我想可能是长时间指手画脚惯了~仔细想了下一些文件操作<br /><br />然后仔细看了一下二进制文件和文本文件，这也是纠正之前的一些疑惑。<br />基本概念是:<br />我自己感觉文本文件和二进制文件没啥区别，文本文件就是有明确普通解码方式的显示字符的文件，可以理解说文本文件也是一种二进制文件，只不过这个二进制文件的解码方式是固定好的(ASCII/UTF-8之类)<br /><br />然后就是读写文本文件时在Windows上有一些转换，写的时候会在\n前面自动加上\r，读的时候反过来，Linux则没有区别。<br /><br />有一件事情是要明确知道的<br />像printf之类的东西，帮助我们输出的，其实我们往printf里面塞的是 int 值，这是一个二进制的值，但是我们从stdout中看到的则已经变成了字符，一定有人帮忙做了转换.<br />我原本以为printf会是检查目标文件，如果目标文件为二进制则直接输出原本的值，如果目标为文本文件就输出对应值的字符<br /><br />这种理解是错的，不同的输入输出函数带来了不同的结果<br />类似printf这种格式话输出函数，会把输出内容按照字符以默认的编码方式encode放入文件，所以那个文件里面写的值已经是真实值的一种显示方式(字符)了<br />然后scanf这种函数在读的之后，也会把字符转换为对应的值，一般ASCII就直接 -0x30了<br /><br />像read/write这种function他们不会做任何转换，直接就把值放进去了，所以你用文本文件打开的时候，按照默认的decode方式来解析他的时候会发现是乱码。<br /><br />这个东西与文本文件二进制文件没有关系。<br />不知道是不是我自己很弱，现在才知道这个东西。<br /><br /><span style="background-color: yellow">作业终于开始:</span><br />3.1 这章主要讲文件Unbuffered IO，这里的unbuffered是指userspace没有buffer来缓冲，kernel一定还是有缓冲的，一般userspace的缓冲做在标准C lib中<br />另外像Android这种架构Java layer会做缓冲(BufferedInputStream/BufferedOutputStream, 默认是8K)<br />Java layer的缓冲可以减少 JNI 调用次数<br />C lib缓冲可以减少 system call 的次数<br /><br />3.2 自己实现dup2<br />不能用fcntl那就只能用dup了<br />这里是想要让做题的人知道，kernel对进程文件描述符的分配原则是 "取最小的没有使用的"<br />所以用dup实现Mydup(fd1, fd2)<br />1.fd2 &lt; fd1: close fd2; dup(fd1)得到的值就是fd2<br />2.fd2 = fd1: 直接return fd1<br />3.fd2 &gt; fd1: 那就只能无限dup了，直到返回值为fd2，然后close掉 fd1 ~ fd2-1<br />这里需要对文件描述符表，文件表，inode之类的概念熟悉。<br /><br />3.3<br />这里主要是要说文件表项的分配，每次open kernel都会分配新的文件表项，dup的作用就是拿到另外一个文件描述符指向相同的文件表项，但是每支文件只有同一份<br />inode。<br />fd1，fd2会指向同一份文件表项<br />fd1，fd2，fd3的文件表项会指向同一份inode<br />fcntl 作用于fd1，F_SETFD用来设定 close_on_exec 标志这个东西是在文件描述符中的，所以只会影响fd1<br />如果是F_SETFL则会影响fd1, fd2文件状态标志都放在文件表中。<br /><br />3.4<br />dup2(fd, 0);<br />dup2(fd, 1);<br />dup2(fd, 2);<br />if (fd &gt; 2) close(fd);<br />这个东西的作用应该就是重定向标准输入输出和错误输出到fd.<br /><br />3.5<br />没什么重要的，shell命令一定是从左往右解析执行的<br /><br />3.6<br />虽然是append方式打开，这个东西是针对写，lseek可以自己选定读取位置。<br />write函数是否是会每次先lseek到文件尾部?然后再写，这样之前lseek的设置就无效了<br />小东西验证。</p>
<p>后面贴下代码<br />append会影响每次write，只要是O_APPEND打开，每次write都会添加到文件末尾。<br /><br />Done</p><img src ="http://www.cppblog.com/xieshuo/aggbug/200521.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-05-22 22:58 <a href="http://www.cppblog.com/xieshuo/archive/2013/05/22/200521.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LTZ做作业之APUE1</title><link>http://www.cppblog.com/xieshuo/archive/2013/05/21/200470.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Tue, 21 May 2013 15:25:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/05/21/200470.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/200470.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/05/21/200470.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/200470.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/200470.html</trackback:ping><description><![CDATA[<p><font style="background-color: #cce8cf"></font></p>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">记性不好，所以作业做起来--从第一章开始，期望有始有终</span></font></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">1.1 对根目录（/）来说，没有parent，所以'.' or '..'就没有区别了，可以用ls -li来看inode，/.. 代表他本身</span></font></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">1.2 多实例，Process ID递增，分配Process ID的具体方式--&gt;//TODO:去查情景分析</span></font></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">1.3 const char* 放到perror中不想让perror自己改，其实我觉得strerror也可以const int</span></font></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">1.4 errno related</span></font></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">比较早之前errno是by process的，这并不合适，Linux支持多线程存取errno</span></font></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">extern int* __errno_location(void)</span></font></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">#define errno (* __errno_location())</span></font></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">Macro为一个函数，使得__errno_location有机会返回一个TSL的variable</span></font></div>
<div></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">这里APUE有Wrap一些简单的打error log的函数，由于errno是一个by thread variable，所以必须先保存</span></font></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">要不然后面print之类的system call同样有可能出现error然后覆盖掉errno</span></font></div>
<div></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">有看到变参函数，纠正了我自己长期的一个误区，之前一直以为变参函数只能用在特定的Case下才有用，例如scanf/printf之类的输入输出函数</span></font></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">因为他们都有带类似format的参数，能够通过%d，%c之类的东西找到后面的变参的个数以及类型，今天有去看一下va_list/va_arg/va_end的实现，会发现变参函数是，本来也应该是一种更加common的设计</span></font></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">这里顺带提一下function call的大体流程，这里需要比较多的背景知识，类似函数调用约定，程序内存分布...</span></font></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">找来一张图比较好看Linux process userspace的布局，印象中windows也一样只不过windows默认是2G/2G，linux是大家都知道的1G/3G</span></font></div><font style="background-color: #cce8cf"><br /><font size="3"><img style="width: 350px; height: 370px" height="370" alt="" src="http://www.cppblog.com/images/cppblog_com/xieshuo/Memory.png" width="350" border="0" longdesc="" /></font><br />
<div>userspace从0~0xC0000000，kernel space(0xC0000000~0xffffffff)的样子跟这个差别比较大，那边分vmalloc/kmalloc还有类似high memory的概念，这里主要贴出userspace，可以看一下RO，RW，ZI，Heap的位置，顺便提一下整个linux virtual memory其实都可以分为两部分: anonymous memory/mapped memory，像RO就是mapped memory，RW开始是mapped memory，只要有人改变初始值，那就会变成anonymous memory，ZI，Heap，Stack这些都是anonymous memory，与函数调用相关的主要是stack --&gt;stack的地址是向低地址增长的，栈底在高地址，栈顶在低地址</div>
<div></div>
<div>然后介绍两种常用的函数调用约定，一种是C语言默认的函数调用约定 __cdecl; 另外一种是PASCAL默认的调用约定 __stdcall</div>
<div>这两种都是从右到左将参数压栈，然后再push ebp; mov ebp, esp; 再然后压入函数局部变量，不一样的是cdecl是由caller function将函数参数出栈，stdcall是由callee function将函数出栈。</div>
<div></div>
<div>这两种方式各有好处，慨括讲一下cdecl的话每个调用者都必须去做pop stack的动作，code size会变大；stdcall则在callee function本身来看会比较单纯</div>
<div>但是这种类型比较难从编译器的角度来支持变参函数。</div>
<div></div>
<div>变参函数都是cdecl</div>
<div>可以玩一下这样的函数...</div></font>
<p>&nbsp;</p><font style="background-color: #cce8cf">
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080">&nbsp;1</span><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="color: #000000">#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">cstdlib</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;2</span><span style="color: #000000"><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">iostream</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /></span><span style="color: #008080">&nbsp;3</span><span style="color: #000000"><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /></span><span style="color: #008080">&nbsp;4</span><span style="color: #000000"><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="color: #0000ff">using</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">namespace</span><span style="color: #000000">&nbsp;std;<br /></span><span style="color: #008080">&nbsp;5</span><span style="color: #000000"><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /></span><span style="color: #008080">&nbsp;6</span><span style="color: #000000"><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;foo(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;cnt,&nbsp;<img alt="" src="http://www.cppblog.com/Images/dot.gif" />)<br /></span><span style="color: #008080">&nbsp;7</span><span style="color: #000000"><img id="Codehighlighter1_85_251_Open_Image" onclick="this.style.display='none'; Codehighlighter1_85_251_Open_Text.style.display='none'; Codehighlighter1_85_251_Closed_Image.style.display='inline'; Codehighlighter1_85_251_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_85_251_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_85_251_Closed_Text.style.display='none'; Codehighlighter1_85_251_Open_Image.style.display='inline'; Codehighlighter1_85_251_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span id="Codehighlighter1_85_251_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_85_251_Open_Text"><span style="color: #000000">{<br /></span><span style="color: #008080">&nbsp;8</span><span style="color: #000000"><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">start&nbsp;foo</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">&nbsp;endl;&nbsp;<br /></span><span style="color: #008080">&nbsp;9</span><span style="color: #000000"><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;p&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&amp;</span><span style="color: #000000">cnt;<br /></span><span style="color: #008080">10</span><span style="color: #000000"><img id="Codehighlighter1_172_218_Open_Image" onclick="this.style.display='none'; Codehighlighter1_172_218_Open_Text.style.display='none'; Codehighlighter1_172_218_Closed_Image.style.display='inline'; Codehighlighter1_172_218_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img id="Codehighlighter1_172_218_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_172_218_Closed_Text.style.display='none'; Codehighlighter1_172_218_Open_Image.style.display='inline'; Codehighlighter1_172_218_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;&nbsp;i&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">&nbsp;cnt;&nbsp;i</span><span style="color: #000000">++</span><span style="color: #000000">)</span><span id="Codehighlighter1_172_218_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_172_218_Open_Text"><span style="color: #000000">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /></span><span style="color: #008080">11</span><span style="color: #000000"><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">(</span><span style="color: #000000">++</span><span style="color: #000000">p)&nbsp;</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">&nbsp;endl;<br /></span><span style="color: #008080">12</span><span style="color: #000000"><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /></span><span style="color: #008080">13</span><span style="color: #000000"><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">end&nbsp;foo</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">&nbsp;endl;<br /></span><span style="color: #008080">14</span><span style="color: #000000"><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="color: #000000"><br /></span><span style="color: #008080">15</span><span style="color: #000000"><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /></span><span style="color: #008080">16</span><span style="color: #000000"><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;main(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;argc,&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">argv[])<br /></span><span style="color: #008080">17</span><span style="color: #000000"><img id="Codehighlighter1_287_456_Open_Image" onclick="this.style.display='none'; Codehighlighter1_287_456_Open_Text.style.display='none'; Codehighlighter1_287_456_Closed_Image.style.display='inline'; Codehighlighter1_287_456_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_287_456_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_287_456_Closed_Text.style.display='none'; Codehighlighter1_287_456_Open_Image.style.display='inline'; Codehighlighter1_287_456_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span id="Codehighlighter1_287_456_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_287_456_Open_Text"><span style="color: #000000">{<br /></span><span style="color: #008080">18</span><span style="color: #000000"><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;a&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">1</span><span style="color: #000000">,&nbsp;b&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">3</span><span style="color: #000000">,&nbsp;c&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">5</span><span style="color: #000000">,&nbsp;d&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">7</span><span style="color: #000000">;<br /></span><span style="color: #008080">19</span><span style="color: #000000"><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;(</span><span style="color: #000000">*</span><span style="color: #000000">functest)(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;cnt,&nbsp;<img alt="" src="http://www.cppblog.com/Images/dot.gif" />);<br /></span><span style="color: #008080">20</span><span style="color: #000000"><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;functest&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;foo;<br /></span><span style="color: #008080">21</span><span style="color: #000000"><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;functest(</span><span style="color: #000000">4</span><span style="color: #000000">,&nbsp;a,&nbsp;b,&nbsp;c,&nbsp;d);<br /></span><span style="color: #008080">22</span><span style="color: #000000"><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;system(</span><span style="color: #000000">"</span><span style="color: #000000">PAUSE</span><span style="color: #000000">"</span><span style="color: #000000">);<br /></span><span style="color: #008080">23</span><span style="color: #000000"><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;EXIT_SUCCESS;<br /></span><span style="color: #008080">24</span><span style="color: #000000"><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span></div>
<p><br />加一点对va_list/va_arg/va_end的说法，其实他的实现蛮灵活的</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img id="Codehighlighter1_0_11_Open_Image" onclick="this.style.display='none'; Codehighlighter1_0_11_Open_Text.style.display='none'; Codehighlighter1_0_11_Closed_Image.style.display='inline'; Codehighlighter1_0_11_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_0_11_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_0_11_Closed_Text.style.display='none'; Codehighlighter1_0_11_Open_Image.style.display='inline'; Codehighlighter1_0_11_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top"><span id="Codehighlighter1_0_11_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff">/**/</span><span id="Codehighlighter1_0_11_Open_Text"><span style="color: #808080">///</span><span style="color: #008000">stdarg.h</span><span style="color: #808080"></span></span><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;va_start&nbsp;_crt_va_start</span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;va_arg&nbsp;_crt_va_arg</span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;va_end&nbsp;_crt_va_end&nbsp;&nbsp;</span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img id="Codehighlighter1_100_111_Open_Image" onclick="this.style.display='none'; Codehighlighter1_100_111_Open_Text.style.display='none'; Codehighlighter1_100_111_Closed_Image.style.display='inline'; Codehighlighter1_100_111_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_100_111_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_100_111_Closed_Text.style.display='none'; Codehighlighter1_100_111_Open_Image.style.display='inline'; Codehighlighter1_100_111_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span id="Codehighlighter1_100_111_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff">/**/</span><span id="Codehighlighter1_100_111_Open_Text"><span style="color: #808080">///</span><span style="color: #008000">vadefs.h</span><span style="color: #808080"></span></span><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;_ADDRESSOF(v)&nbsp;&nbsp;&nbsp;(&nbsp;&amp;reinterpret_cast&lt;const&nbsp;char&nbsp;&amp;&gt;(v)&nbsp;)</span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />typedef&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;&nbsp;va_list;<br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;_INTSIZEOF(n)&nbsp;&nbsp;&nbsp;(&nbsp;(sizeof(n)&nbsp;+&nbsp;sizeof(int)&nbsp;-&nbsp;1)&nbsp;&amp;&nbsp;~(sizeof(int)&nbsp;-&nbsp;1)&nbsp;)</span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;_crt_va_start(ap,v)&nbsp;&nbsp;(&nbsp;ap&nbsp;=&nbsp;(va_list)_ADDRESSOF(v)&nbsp;+&nbsp;_INTSIZEOF(v)&nbsp;)</span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;_crt_va_arg(ap,t)&nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;*(t&nbsp;*)((ap&nbsp;+=&nbsp;_INTSIZEOF(t))&nbsp;-&nbsp;_INTSIZEOF(t))&nbsp;)</span><span style="color: #000000"><br /><img alt="" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;_crt_va_end(ap)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;ap&nbsp;=&nbsp;(va_list)0&nbsp;)</span></div></font>
<p><font style="background-color: #cce8cf"></font></p>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">贴一段网上看到的应该是i386的实现，类似这种变参函数会直接去用指针操作stack来找参数的，因为涉及到对其的问题一定是by platform的，不太好移植</span></font></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">像_INTSIZEOF(n) 就是int对其</span></font></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">大概讲下意思 va_list 就是 char*，是一个用来找参数ptr的游标</span></font></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">va_start(ap, v) &nbsp;通过第一个固定参数v 初始化 ap</span></font></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">va_arg(ap, t) &nbsp;这里就给Type t了，所以并不一定需要类似printf的 format 来找，caller和callee可以有一些其他的约定方式，这个返回当前类型为t的参数的值，并且将ap指向下个参数，因为之前ap被初始化的时候其实他并不知道他指向的参数的类型。</span></font></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">va_end(ap) 清掉ap</span></font></div>
<div></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">多说一句，printf系列的函数还蛮多的，fprintf/sprintf/vprintf/svnprintf...带f的是面向FILE streaming的，s是针对char buffer的，v则是说参数是带va_list的，n则是具体指size</span></font></div>
<div></div>
<div><font style="background-color: #cce8cf"><span style="background-color: #ffffff">1.5/1.6讨论32位表示时间溢出的，不想写答案，时间比较晚，第一章作业写完。</span></font></div>
<p>&nbsp;<br /><br /></p>
<p>记录一些关于系统总线与CPU&#8220;位数"的基本概念</p>
<p>通常所说的CPU的位数，32位or64位CPU，指的是ALU(算术逻辑单元)的宽度，也就是这个ALU处理数据的基本单元的宽度<br />所以数据总线基本会和ALU宽度相同(有例外，这个我没想清楚工作原理) --&gt;应该是可以新加一些Module来做转换。<br />而地址总线则是CPU寻址的能力，一个是怎么去寻址，一个是寻到地址后，地址中内容的宽度(当然这个宽度跟地址类型(byte，short，int)有关，但送给CPU的时候一般是单位次数送数据总线的宽度的数据)，地址总线决定CPU能访问的Memory的范围。</p>
<p>8086是16位ALU 20位数据总线寻址1M<br />每次CPU送出的地址都是16位，然后加上段寄存器作为最高4位 </p>
<p>&nbsp;</p> <img src ="http://www.cppblog.com/xieshuo/aggbug/200470.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-05-21 23:25 <a href="http://www.cppblog.com/xieshuo/archive/2013/05/21/200470.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>APUE杂记</title><link>http://www.cppblog.com/xieshuo/archive/2013/05/19/200399.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Sun, 19 May 2013 07:17:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/05/19/200399.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/200399.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/05/19/200399.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/200399.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/200399.html</trackback:ping><description><![CDATA[<p>这里会记录一些比较杂乱的段落，作为APUE作业的开始，以后会增添，或许还会整理，比较确定的是会贴一些章节作业上来，我目前不知道难度，初始想法是单看看书，如果可以会去翻翻情景分析，因为我身边也正好还有一本。我想老头子正式开工了...监督自己，期望能完成有收获。</p><img src ="http://www.cppblog.com/xieshuo/aggbug/200399.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-05-19 15:17 <a href="http://www.cppblog.com/xieshuo/archive/2013/05/19/200399.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>