﻿<?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++博客-mysileng-随笔分类-linux编程</title><link>http://www.cppblog.com/mysileng/category/20226.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 24 Sep 2014 07:57:57 GMT</lastBuildDate><pubDate>Wed, 24 Sep 2014 07:57:57 GMT</pubDate><ttl>60</ttl><item><title>cmake与boost (muduo的准备工作)</title><link>http://www.cppblog.com/mysileng/archive/2014/09/23/208383.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Tue, 23 Sep 2014 01:29:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2014/09/23/208383.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/208383.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2014/09/23/208383.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/208383.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/208383.html</trackback:ping><description><![CDATA[<div><span style="font-size: 18pt">一、</span><span class="tcnt"><font size="6"><span style="font-size: 18pt">linux下安装cmake<br />
<p>首先下载源码包<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.cmake.org/cmake/resources/software.html" rel="nofollow" target="_blank"> http://www.cmake.org/cmake/resources/software.html</a></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这里下载的是cmake-2.8.9.tar.gz</p>
<p>随便找个目录解压缩</p>
<div id="highlighter_106660">
<div>
<div>
<table>
<tbody>
<tr>
<td><code>1</code></td>
<td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>tar</code> <code>-xzvf cmake-2.8.9.</code><code>tar</code><code>.gz</code></td></tr></tbody></table></div>
<div>
<table>
<tbody>
<tr>
<td><code>2</code></td>
<td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>cd</code> <code>cmake-cmake-2.8.9</code></td></tr></tbody></table></div></div></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;依次执行：</p>
<div id="highlighter_88772">
<div>
<div>
<table>
<tbody>
<tr>
<td><code>1</code></td>
<td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>./bootstrap</code></td></tr></tbody></table></div>
<div>
<table>
<tbody>
<tr>
<td><code>2</code></td>
<td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>make</code></td></tr></tbody></table></div>
<div>
<table>
<tbody>
<tr>
<td><code>3</code></td>
<td style="height: 22px; width: 220px"><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>make</code> <code>install</code></td></tr></tbody></table></div></div></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmake 会默认安装在 /usr/local/bin 下面</p>
<p>要改变安装路径，在bootstrap命令中加入'--pr<span style="font-size: 18pt">ef</span>ix=PATH'选项。 </p></span></font></span><br /><span style="font-size: 18pt">二、</span><span class="tcnt"><font size="6"><span style="font-size: 18pt">linux下安装boost<br />linux平台下要编译安装除gcc和gcc-c++之外，还需要两个开发库：bzip2-devel 和python-devel，因此在安装前应该先保证这两个库已经安装：<br /><pre class="prettyprint"><p><span class="com">#yum install gcc gcc-c++ bzip2 bzip2-devel bzip2-libs python-devel -y</span><br /></p></pre>然后是去官网下载源码包，<a href="http://www.boost.org/users/download/" rel="nofollow" target="_blank">地址</a><br />下载，解压，按照如下步骤：<br /><pre class="prettyprint"><p><span class="com">#tar xvzf boost_1_50_0.tar.gz</span></p></pre>进入boost_1_50_0目录：<br /><pre class="prettyprint"><p><span class="com">#cd boost_1_50_0</span><br /></p></pre>
<p>然后是编译安装，boost源码包中有配置脚本，直接用就可以：</p><pre class="prettyprint"><p><span class="com">#sh ./bootstrap.sh</span></p><p><span class="com">Building Boost.Build engine with toolset gcc... tools/build/v2/engine/bin.linuxx86_64/b2</span><br /><span class="typ">Detecting</span><span class="pln"> </span><span class="typ">Python</span><span class="pln"> version</span><span class="pun">...</span><span class="pln"> </span><span class="lit">2.6</span><br /><span class="typ">Detecting</span><span class="pln"> </span><span class="typ">Python</span><span class="pln"> root</span><span class="pun">...</span><span class="pln"> </span><span class="pun">/</span><span class="pln">usr</span><br /><span class="typ">Unicode</span><span class="pun">/</span><span class="pln">ICU support </span><span class="kwd">for</span><span class="pln"> </span><span class="typ">Boost</span><span class="pun">.</span><span class="typ">Regex</span><span class="pun">?...</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> found</span><span class="pun">.</span><br /><span class="typ">Generating</span><span class="pln"> </span><span class="typ">Boost</span><span class="pun">.</span><span class="typ">Build</span><span class="pln"> configuration </span><span class="kwd">in</span><span class="pln"> project</span><span class="pun">-</span><span class="pln">config</span><span class="pun">.</span><span class="pln">jam</span><span class="pun">...</span><br /><br /><span class="typ">Bootstrapping</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">done</span><span class="pun">.</span><span class="pln"> </span><span class="typ">To</span><span class="pln"> build</span><span class="pun">,</span><span class="pln"> run</span><span class="pun">:</span><br /><br /><span class="pln">    </span><span class="pun">./</span><span class="pln">b2</span><br /><span class="pln">    </span><br /><span class="typ">To</span><span class="pln"> adjust configuration</span><span class="pun">,</span><span class="pln"> edit </span><span class="str">'project-config.jam'</span><span class="pun">.</span><br /><span class="typ">Further</span><span class="pln"> information</span><span class="pun">:</span><br /><br /><span class="pln">   </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Command</span><span class="pln"> line help</span><span class="pun">:</span><br /><span class="pln">     </span><span class="pun">./</span><span class="pln">b2 </span><span class="pun">--</span><span class="pln">help</span><br /><span class="pln">     </span><br /><span class="pln">   </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Getting</span><span class="pln"> started guide</span><span class="pun">:</span><span class="pln"> </span><br /><span class="pln">     http</span><span class="pun">:</span><span class="com">//www.boost.org/more/getting_started/unix-variants.html</span><br /><span class="pln">     </span><br /><span class="pln">   </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Boost</span><span class="pun">.</span><span class="typ">Build</span><span class="pln"> documentation</span><span class="pun">:</span><br /><span class="pln">     http</span><span class="pun">:</span><span class="com">//www.boost.org/boost-build2/doc/html/index.html</span><br /><br /></p></pre>接下来就是编译，重点关注是否编译成功：<br /><pre class="prettyprint"><p><span class="com">#./b2</span><br /></p></pre>然后就是漫长的等待，如果最后出现：<br /><pre class="prettyprint"><p><font color="#ff0000"><span class="typ">The</span><span class="pln"> </span><span class="typ">Boost</span><span class="pln"> C</span><span class="pun">++</span><span class="pln"> </span><span class="typ">Libraries</span><span class="pln"> were successfully built</span><span class="pun">!</span></font><br /><span class="pln">          </span><br /><span class="typ">The</span><span class="pln"> following directory should be added to compiler include paths</span><span class="pun">:</span><br /><span class="pln">          </span><br /><span class="pln">    </span><span class="str">/home/</span><span class="pln">gang</span><span class="pun">/</span><span class="pln">BAK</span><span class="pun">/</span><span class="pln">boost_1_50_0</span><br /><span class="pln">      </span><br /><span class="typ">The</span><span class="pln"> following directory should be added to linker library paths</span><span class="pun">:</span><br /><span class="pln">      </span><br /><span class="pln">    </span><span class="str">/home/</span><span class="pln">gang</span><span class="pun">/</span><span class="pln">BAK</span><span class="pun">/</span><span class="pln">boost_1_50_0</span><span class="pun">/</span><span class="pln">stage</span><span class="pun">/</span><span class="pln">lib</span><br /><br /></p></pre>表示编译成功，如果没有成功，就需要回查看哪里出现error，再安装相应的库，<br />最后就是安装：<br /><pre class="prettyprint"><p><span class="com">#./b2 install --prefix=/usr/local</span><br /></p></pre>安装后的头文件在/usr/local/include/boost里面，而相应的库在/usr/local/lib/libboost_*</span></font></span></div><img src ="http://www.cppblog.com/mysileng/aggbug/208383.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2014-09-23 09:29 <a href="http://www.cppblog.com/mysileng/archive/2014/09/23/208383.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>并行编程——并发级别 </title><link>http://www.cppblog.com/mysileng/archive/2014/09/12/208282.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Fri, 12 Sep 2014 05:05:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2014/09/12/208282.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/208282.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2014/09/12/208282.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/208282.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/208282.html</trackback:ping><description><![CDATA[<p class="a">转自：<a href="http://www.cnblogs.com/jiayy/p/3246167.html">http://www.cnblogs.com/jiayy/p/3246167.html</a><br /><br />在看多核编程相关论文时，往往一个并发算法会说自己是wait-free的或者lock-free的，或者是 non-blocking 的，这些专有词汇其实表示的是并发的程度，或者说并发的级别。并发级别的理解是阅读各种并发算法设计论文以及并发数据结构实现的必备基础。</p>
<p class="2">1.1 &nbsp;Wait-freedom 无等待并发</p>
<p class="a">Wait-freedom 指的是每一个线程都一直运行下去而无须等待外部条件，整个流程中任何操作都能在一个有限的步骤内完成，这是最高的并发级别，没有任何阻塞。</p>
<p class="a">&nbsp;结合之前原子操作部分的知识，可以简单认为能够直接调用一个原子操作实现的算法或程序就属于Wait-free，比如下面的 increment_reference_counter 函数就是wait-free的，它封装了atomic_increment这个原子自增原语，多个线程可以同时调用这个函数对同一个内存变量进行自增，而无须任何阻塞（其实也是有阻塞的，是总线锁级别）</p>
<p class="a">&nbsp;与此做对比，CAS类的调用就不是wait-free的，注意wait-free的原语都不能包含内部循环，CAS原语使用时通常包含在&#8220;循环直到成功&#8221;的循环内部。</p>
<blockquote style="margin-right: 0px" dir="ltr">
<p class="a">&nbsp;void increment_reference_counter(rc_base* obj)</p>
<p class="a">{</p>
<p class="a">&nbsp;&nbsp;&nbsp; atomic_increment(obj-&gt;rc);</p>
<p class="a">}</p></blockquote>
<p class="2">1.2 &nbsp;Lock-freedom 无锁并发</p>
<p class="a">Lock-freedom 指的是整个系统作为一个整体一直运行下去，系统内部单个线程某段时间内可能会饥饿，这是比wait-freedom弱的并发级别，但系统整体上看依然是没有阻塞的。所有wait-free的算法显然都满足lock-free的要求。</p>
<p class="a">&nbsp;Lock-free算法通常可以通过同步原语 CAS实现。</p>
<blockquote style="margin-right: 0px" dir="ltr">
<p class="a">&nbsp;void stack_push(stack* s, node* n)</p>
<p class="a">{</p>
<p class="a">&nbsp;&nbsp;&nbsp; node* head;</p>
<p class="a">&nbsp;&nbsp;&nbsp; do</p>
<p class="a">&nbsp;&nbsp;&nbsp; {</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; head = s-&gt;head;</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n-&gt;next = head;</p>
<p class="a">&nbsp;&nbsp;&nbsp; }</p>
<p class="a">&nbsp;&nbsp;&nbsp; while ( ! atomic_compare_exchange(s-&gt;head, head, n));</p>
<p class="a">}</p></blockquote>
<p class="a">多个线程同时调用上述函数，理论上某个线程可以一直困在循环内部，但一旦有一个线程原子操作失败而返回循环，意味着有其他线程成功执行了原子操作而退出循环，从而保证系统整体是没有阻塞的。</p>
<p class="a">&nbsp;其实前面的原子自增函数也可以用下面的原语实现，在这种实现里，不再是所有线程都无阻塞了，某些线程可能会因为CAS失败而回绕若干次循环。</p>
<blockquote style="margin-right: 0px" dir="ltr">
<p class="a">void increment_reference_counter(rc_base* obj)</p>
<p class="a">{</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Int rc;</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Do {</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rc = obj-&gt;rc;</p>
<p class="a">} while(!atomic_compare_exchange(obj-&gt;rc,rc,rc+1));</p>
<p class="a">}</p></blockquote>
<p class="2">1.3 &nbsp;Obstruction-freedom 无阻塞并发</p>
<p class="a">Obstruction-free 是指在任何时间点，一个孤立运行线程的每一个操作可以在有限步之内结束。只要没有竞争，线程就可以持续运行，一旦共享数据被修改，Obstruction-free 要求中止已经完成的部分操作，并进行回滚，obstruction-free 是并发级别更低的非阻塞并发，该算法在不出现冲突性操作的情况下提供单线程式的执行进度保证，所有 Lock-Free 的算法都是 Obstruction-free 的。</p>
<p class="2">1.4 &nbsp;Blocking algoithms 阻塞并发</p>
<p class="a">阻塞类的算法是并发级别最低的同步算法，它一般需要产生阻塞。可以简单认为基于锁的实现是blocking的算法。详细参考第五章</p>
<p class="a">上述几种并发级别可以使用下图描述：<br />蓝色是阻塞的算法，绿色是非阻塞算法，金字塔越上方，并发级别越高，性能越好，右边的金字塔是实现工具（原子操作、锁、互斥体等）<img style="border-top-color: ; border-bottom-color: ; border-right-color: ; border-left-color: " border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/mysileng/QQ截图20140912130216.jpg" width="1111" height="592" /><br /><br /></p><img src ="http://www.cppblog.com/mysileng/aggbug/208282.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2014-09-12 13:05 <a href="http://www.cppblog.com/mysileng/archive/2014/09/12/208282.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>lock free的理解</title><link>http://www.cppblog.com/mysileng/archive/2014/09/03/208222.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Wed, 03 Sep 2014 13:11:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2014/09/03/208222.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/208222.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2014/09/03/208222.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/208222.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/208222.html</trackback:ping><description><![CDATA[<div>转自：<a href="http://www.isnowfy.com/understand-to-lock-free/">http://www.isnowfy.com/understand-to-lock-free/</a><br /><br />
<p>以前一直不明白lock free是什么，后来发现原来是完全理解错了概念，lock free看到大家有的翻译为无锁，有的翻译为锁无关，其实用不用锁和lock free是不相关的，用了锁也可能是lock free，而不用锁有可能不是lock free。<br /><span id="more-962"></span></p>
<p>一个lock free的解释是</p>
<blockquote>
<p>一个&#8220;锁无关&#8221;的程序能够确保执行它的所有线程中至少有一个能够继续往下执行。 </p></blockquote>
<p>其实看我们那副图就是说你的各个线程不会互相阻塞，那么你的程序才能成为lock free的。像我们平常用的互斥锁，当有线程获得锁，其他线程就被阻塞掉了，这里的问题就是如果获得锁的线程挂掉了，而且锁也没有释放，那么整个程序其实就被block在那了，而如果程序是lock free的那么即使有线程挂掉，也不影响整个程序继续向下进行，也就是系统在整体上而言是一直前进的。</p>
<p>那么，不用锁就是lock free的吗，一开始就提到了，不用锁也可能不是lock free的，举个例子</p>
<div class="geshi no c">
<ol><li class="li1">
<div class="de1"><span class="kw1">while</span> <span class="br0">(</span>x <span class="sy0">==</span> <span class="nu0">0</span><span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1">
<div class="de1">&nbsp; &nbsp; x <span class="sy0">=</span> <span class="nu0">1</span><span class="sy0">-</span>x;</div></li><li class="li1">
<div class="de1"><span class="br0">}</span></div></li></ol></div>
<p>在这里如果两个线程同时执行，可能同时进入while循环，然后x两次改变值之后，依然是0，那么两个线程就会一直互相在这里阻塞掉了，所以这里虽然没有锁，依然不是lock free的。</p>
<p>现在大家写lock free的时候一般都会使用CAS（compare and set）操作来写，因为现在很多的cpu都是支持CAS操作并作为原子操作来处理的，CAS操作一般是这样的</p>
<div class="geshi no c">
<ol><li class="li1">
<div class="de1">bool compare_and_swap <span class="br0">(</span><span class="kw4">int</span> <span class="sy0">*</span>oldval, <span class="kw4">int</span> <span class="sy0">*</span>dest, <span class="kw4">int</span> newval<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1">
<div class="de1">&nbsp; <span class="kw1">if</span> <span class="br0">(</span><span class="sy0">*</span>oldval <span class="sy0">==</span> <span class="sy0">*</span>dest<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="sy0">*</span>dest <span class="sy0">=</span> newval;</div></li><li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">true</span>;</div></li><li class="li1">
<div class="de1">&nbsp; <span class="br0">}</span></div></li><li class="li1">
<div class="de1">&nbsp; <span class="kw1">return</span> <span class="kw2">false</span>;</div></li><li class="li1">
<div class="de1"><span class="br0">}</span></div></li></ol></div>
<p>其实这样一个操作和乐观锁很像，并且操作简单，相应的比互斥锁的代价要小。所以现在大家都是喜欢用lock free的技术来提高系统的performance。</p>
<p>最后如果大家对于如何编写lock free的数据结构感兴趣的话，可以参考我后面给出的链接。</p>
<p><a href="http://www.searchtb.com/2012/10/introduction_to_disruptor.html">一种高效无锁内存队列的实现</a><br /><a href="http://coolshell.cn/articles/8239.html">无锁队列的实现</a><br /><a href="http://blog.csdn.net/pongba/article/details/588638">锁无关的(Lock-Free)数据结构</a><br /><a href="http://preshing.com/20120612/an-introduction-to-lock-free-programming/">An Introduction to Lock-Free Programming</a></p></div><img src ="http://www.cppblog.com/mysileng/aggbug/208222.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2014-09-03 21:11 <a href="http://www.cppblog.com/mysileng/archive/2014/09/03/208222.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>客户端connect()函数阻塞问题解决</title><link>http://www.cppblog.com/mysileng/archive/2014/08/23/208106.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Sat, 23 Aug 2014 09:01:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2014/08/23/208106.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/208106.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2014/08/23/208106.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/208106.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/208106.html</trackback:ping><description><![CDATA[<p><font color="#00ffff" size="4" face="宋体"><strong>转自：<a href="http://zhucuicui.96986.blog.163.com/blog/static/5833370220136219016445/">http://zhucuicui.96986.blog.163.com/blog/static/5833370220136219016445/</a><br /><br />建立socket后默认connect()函数为阻塞连接状态，在大多数实现中，connect的超时时间在75s至几分钟之间，想要缩短超时时间，可解决问题的两种方法：方法一、将socket句柄设置为非阻塞状态，方法二、采用信号处理函数设置阻塞超时控制。</strong></font></p>
<p><font face="宋体">在一个TCP套接口被设置为非阻塞之后调用connect,connect会立即返回EINPROGRESS错误,表示连接操作正在进行中,但是仍未完成;同时TCP的三路握手操作继续进行;在这之后,我们可以调用select来检查这个链接是否建立成功;非阻塞connect有三种用途:<br />1.我们可以在三路握手的同时做一些其它的处理.connect操作要花一个往返时间完成,而且可以是在任何地方,从几个毫秒的局域网到几百毫秒或几秒的广域网.在这段时间内我们可能有一些其他的处理想要执行;<br />2.可以用这种技术同时建立多个连接.在Web浏览器中很普遍;<br />3.由于我们使用select来等待连接的完成,因此我们可以给select设置一个时间限制,从而缩短connect的超时时间.在大多数实现中,connect的超时时间在75秒到几分钟之间.有时候应用程序想要一个更短的超时时间,使用非阻塞connect就是一种方法;<br />非阻塞connect听起来虽然简单,但是仍然有一些细节问题要处理:<br />1.即使套接口是非阻塞的,如果连接的服务器在同一台主机上,那么在调用connect建立连接时,连接通常会立即建立成功.我们必须处理这种情况;<br />2.源自Berkeley的实现(和Posix.1g)有两条与select和非阻塞IO相关的规则:<br />A:当连接建立成功时,套接口描述符变成可写;<br />B:当连接出错时,套接口描述符变成既可读又可写;<br /><strong><font color="#0000ff">注意</font></strong>:当一个套接口出错时,它会被select调用标记为既可读又可写;</font></p>
<p><font face="宋体">非阻塞connect有这么多好处,但是处理非阻塞connect时会遇到很多可移植性问题;</font></p>
<p><font face="宋体"><font color="#0000ff">处理非阻塞connect的步骤:</font><br />第一步:创建socket,返回套接口描述符;<br />第二步:调用fcntl把套接口描述符设置成非阻塞;<br />第三步:调用connect开始建立连接;<br />第四步:判断连接是否成功建立;<br />A:如果connect返回0,表示连接简称成功(服务器可客户端在同一台机器上时就有可能发生这种情况);<br />B:调用select来等待连接建立成功完成;<br />如果select返回0,则表示建立连接超时;我们返回超时错误给用户,同时关闭连接,以防止三路握手操作继续进行下去;<br />如果select返回大于0的值,则需要检查套接口描述符是否可读或可写;如果套接口描述符可读或可写,则我们可以通过调用getsockopt来得到套接口上待处理的错误(SO_ERROR),如果连接建立成功,这个错误值将是0,如果建立连接时遇到错误,则这个值是连接错误所对应的errno值(比如:ECONNREFUSED,ETIMEDOUT等).<br />"读取套接口上的错误"是遇到的第一个可移植性问题;如果出现问题,getsockopt源自Berkeley的实现是返回0,等待处理的错误在变量errno中返回;但是Solaris会让getsockopt返回-1,errno置为待处理的错误;我们对这两种情况都要处理;</font></p>
<p><font face="宋体">这样,在处理非阻塞connect时,在不同的套接口实现的平台中存在的移植性问题,首先,有可能在调用select之前,连接就已经建立成功,而且对方的数据已经到来.在这种情况下,连接成功时套接口将既可读又可写.这和连接失败时是一样的.这个时候我们还得通过getsockopt来读取错误值;这是第二个可移植性问题;<br /><font color="#0000ff">移植性问题总结</font>:<br />1.对于出错的套接口描述符,getsockopt的返回值源自Berkeley的实现是返回0,待处理的错误值存储在errno中;而源自Solaris的实现是返回0,待处理的错误存储在errno中;(套接口描述符出错时调用getsockopt的返回值不可移植)<br />2.有可能在调用select之前,连接就已经建立成功,而且对方的数据已经到来,在这种情况下,套接口描述符是既可读又可写;这与套接口描述符出错时是一样的;(怎样判断连接是否建立成功的条件不可移植)</font></p>
<p><font face="宋体">这样的话,在我们判断连接是否建立成功的条件不唯一时,我们<strong><font color="#0000ff">可以有以下的方法来解决这个问题</font></strong>:<br />1.调用getpeername代替getsockopt.如果调用getpeername失败,getpeername返回ENOTCONN,表示连接建立失败,我们必须以SO_ERROR调用getsockopt得到套接口描述符上的待处理错误;<br />2.调用read,读取长度为0字节的数据.如果read调用失败,则表示连接建立失败,而且read返回的errno指明了连接失败的原因.如果连接建立成功,read应该返回0;<br />3.再调用一次connect.它应该失败,如果错误errno是EISCONN,就表示套接口已经建立,而且第一次连接是成功的;否则,连接就是失败的;</font></p>
<p><font face="宋体"><strong><font color="#0000ff">被中断的connect</font></strong>:<br />如果在一个阻塞式套接口上调用connect,在TCP的三路握手操作完成之前被中断了,比如说,被捕获的信号中断,将会发生什么呢?假定connect不会自动重启,它将返回EINTR.那么,这个时候,我们就不能再调用connect等待连接建立完成了,如果再次调用connect来等待连接建立完成的话,connect将会返回错误值EADDRINUSE.在这种情况下,应该做的是调用select,就像在非阻塞式connect中所做的一样.然后,select在连接建立成功(使套接口描述符可写)或连接建立失败(使套接口描述符既可读又可写)时返回;</font></p>
<p><font color="#00ffff" size="4" face="宋体"><strong>方法二、定义信号处理函数：</strong></font></p>
<p>&nbsp;</p>
<ol style="padding-bottom: 5px; padding-top: 5px; margin: 0px 1px 0px 0px" sizcache="2.6838.895891" sizset="false"><li>sigset<span style="color: #0000cc">(</span>SIGALRM<span style="color: #0000cc">,</span> u_alarm_handler<span style="color: #0000cc">)</span><span style="color: #0000cc">;</span><br /></li><li>alarm<span style="color: #0000cc">(</span>2<span style="color: #0000cc">)</span><span style="color: #0000cc">;</span><br /></li><li>code <span style="color: #0000cc">=</span> connect<span style="color: #0000cc">(</span>socket_fd<span style="color: #0000cc">,</span> <span style="color: #0000cc">(</span>struct sockaddr<span style="color: #0000cc">*</span><span style="color: #0000cc">)</span><span style="color: #0000cc">&amp;</span>socket_st<span style="color: #0000cc">,</span> sizeof<span style="color: #0000cc">(</span>struct sockaddr_in<span style="color: #0000cc">)</span><span style="color: #0000cc">)</span><span style="color: #0000cc">;</span><br /></li><li>alarm<span style="color: #0000cc">(</span>0<span style="color: #0000cc">)</span><span style="color: #0000cc">;</span><br /></li><li>sigrelse<span style="color: #0000cc">(</span>SIGALRM<span style="color: #0000cc">)</span><span style="color: #0000cc">;</span></li></ol>
<p>首先定义一个中断信号处理函数u_alarm_handler，用于超时后的报警处理，然后定义一个2秒的定时器，执行connect，当系统connect成功，则系统正常执行下去；如果connect不成功阻塞在这里，则超过定义的2秒后，系统会产生一个信号，触发执行u_alarm_handler函数， 当执行完u_alarm_handler后，程序将继续从connect的下面一行执行下去。<br />其中，处理函数可以如下定义，也可以加入更多的错误处理。<br /></p>
<ol style="padding-bottom: 5px; padding-top: 5px; margin: 0px 1px 0px 0px" sizcache="2.7252.950130" sizset="false"><li>void u_alarm_handler()</li><li>{</li><li>}</li></ol> <img src ="http://www.cppblog.com/mysileng/aggbug/208106.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2014-08-23 17:01 <a href="http://www.cppblog.com/mysileng/archive/2014/08/23/208106.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>惊群现象</title><link>http://www.cppblog.com/mysileng/archive/2014/08/07/207932.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Thu, 07 Aug 2014 06:21:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2014/08/07/207932.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/207932.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2014/08/07/207932.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/207932.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/207932.html</trackback:ping><description><![CDATA[引用：http://www.cppblog.com/isware/archive/2011/07/20/151470.aspx<br />-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------<br />&#8220;据说&#8221;惊群问题已经是一个很古老的问题了，并且在大多数系统中<a href="http://simohayha.iteye.com/blog/561424" rel="nofollow">已经得到有效解决</a>，但对我来说，仍旧是一个比较新的概念，因此有必要记录一下。<br /><br /><strong style="font-size: 14pt">什么是惊群</strong><br style="font-size: 14pt" /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 举一个很简单的例子，当你往一群鸽子中间扔一块食物，虽然最终只有一个鸽子抢到食物，但所有鸽子都会被惊动来争夺，没有抢到食物的鸽子只好回去继续睡觉， 等待下一块食物到来。这样，每扔一块食物，都会惊动所有的鸽子，即为惊群。对于操作系统来说，多个进程/线程在等待同一资源是，也会产生类似的效果，其结 果就是每当资源可用，所有的进程/线程都来竞争资源，造成的后果：<br />1）系统对用户进程/线程频繁的做无效的调度、上下文切换，系统系能大打折扣。<br />2）为了确保只有一个线程得到资源，用户必须对资源操作进行加锁保护，进一步加大了系统开销。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最常见的例子就是对于socket描述符的accept操作，当多个用户进程/线程监听在同一个端口上时，由于实际只可能accept一次，因此就会产生惊群现象，当然前面已经说过了，这个问题是一个古老的问题，新的操作系统内核已经解决了这一问题。<br /><br /><strong style="font-size: 14pt">linux内核解决惊群问题的方法</strong><br style="font-size: 14pt" /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对于一些已知的惊群问题，内核开发者增加了一个&#8220;互斥等待&#8221;选项。一个互斥等待的行为与睡眠基本类似，主要的不同点在于：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1）当一个等待队列入口有 WQ_FLAG_EXCLUSEVE 标志置位, 它被添加到等待队列的尾部. 没有这个标志的入口项, 相反, 添加到开始.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2）当 wake_up 被在一个等待队列上调用时, 它在唤醒第一个有 WQ_FLAG_EXCLUSIVE 标志的进程后停止。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 也就是说，对于互斥等待的行为，比如如对一个listen后的socket描述符，多线程阻塞accept时，系统内核只会唤醒所有正在等待此时间的队列 的第一个，队列中的其他人则继续等待下一次事件的发生，这样就避免的多个线程同时监听同一个socket描述符时的惊群问题。<br /><br />根据以上背景信息，我们来比较一下常见的Server端设计方案。<br />
<div>方案1：listen后，启动多个线程(进程)，对此socket进行监听（仅阻塞accept方式不惊群）。<br />方案2：主线程负责监听，通过线程池方式处理连接。（通常的方法）<br />方案3：主线程负责监听，客户端连接上来后由主线程分配实际的端口，客户端根据此端口重新连接，然后处理数据。<br /><br /><strong>先考虑客户端单连接的情况</strong>：<br />方案1：每当有新的连接到来时，系统内核会从队列中以FIFO的方式选择一个监听线程来服务此连接，因此可以充分发挥系统的系能并且多线程负载均衡。对于单连接的场景，这种方案无疑是非常优越的。遗憾的是，对于select、epoll，内核目前无法解决惊群问题。<a href="http://simohayha.iteye.com/blog/658012" rel="nofollow">(nginx对于惊群问题的解决方法)</a><br />方案2：由于只有一个线程在监听，其瞬时的并发处理连接请求的能力必然不如多线程。同时，需要对线程池做调度管理，必然涉及资源共享访问，相对于方案一来说管理成本要增加不少，代码复杂度提高，性能也有所下降。<br />方案3：与方案2有不少类似的地方，其优势是不需要做线程调度。缺点是增加了主线程的负担，除了接收连接外还需要发送数据，而且需要两次连接，孰优孰劣，有待测试。<br /><br /><strong>再考虑客户端多连接的情况：</strong><br />对于数据传输类的应用，为了充分利用带宽，往往会开启多个连接来传输数据，连接之间的数据有相互依赖性，因此Server端要想很好的维护这种依赖性，把同一个客户端的所有连接放在一个线程中处理是非常有必要的。<br /><strong>A、同一客户端在一个线程中处理</strong><br />方案1：如果没有更底层的解决方案的话，Server则需要维护一个全局列表，来记录当前连接请求该由哪个线程处理。多线程需要同时竞争一个全局资源，似乎有些不妙。<br />方案2：主线程负责监听并分发，因此与单连接相比没有带来额外的性能开销。仅仅会造成主线程忙于更多的连接请求。<br />方案3：较单线程来说，主线程工作量没有任何增加，由于多连接而造成的额外开销由实际工作线程分担，因此对于这种场景，方案3似乎是最佳选择。<br /><br /><strong>B、同一客户端在不同线程中处理</strong><br />方案1：同样需要竞争资源。<br />方案2：没理由。<br />方案3：不可能。<br /><br />另外：<br />
<div>(《UNIX网络编程》第三版是在第30章)<br />读《UNIX网络编程》第二版的第一卷时，发现作者在第27章&#8220;客户-服务器程序其它设计方法&#8221;中的27.6节&#8220;TCP预先派生子进程服务器程序，accept无上锁保护&#8221;中提到了一种由子进程去竞争客户端连接的设计方法，用伪码描述如下:<br /><br />服务器主进程:<br /><br />
<table style="border-collapse: collapse" cellspacing="0" cellpadding="0" width="95%" bgcolor="#f1f1f1" border="1">
<tbody>
<tr>
<td>
<p style="margin: 5px; line-height: 150%"><code><span style="color: #000000">listen_fd <span style="color: #0000cc">=</span> <span style="color: #ff0000">socket</span><span style="color: #0000cc">(</span><span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">)</span><span style="color: #0000cc">;</span><br /><span style="color: #ff0000">bind</span><span style="color: #0000cc">(</span>listen_fd<span style="color: #0000cc">,</span> <span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">)</span><span style="color: #0000cc">;</span><br /><span style="color: #ff0000">listen</span><span style="color: #0000cc">(</span>listen_fd<span style="color: #0000cc">,</span> <span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">)</span><span style="color: #0000cc">;</span><br />pre_fork_children<span style="color: #0000cc">(</span><span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">)</span><span style="color: #0000cc">;</span><br /><span style="color: #ff0000">close</span><span style="color: #0000cc">(</span>listen_fd<span style="color: #0000cc">)</span><span style="color: #0000cc">;</span><br />wait_children_die<span style="color: #0000cc">(</span><span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">)</span><span style="color: #0000cc">;</span><br /></span></code></p></td></tr></tbody></table><br />服务器服务子进程:<br /><br />
<table style="border-collapse: collapse" cellspacing="0" cellpadding="0" width="95%" bgcolor="#f1f1f1" border="1">
<tbody>
<tr>
<td>
<p style="margin: 5px; line-height: 150%"><code><span style="color: #000000"><span style="color: #0000ff">while</span> <span style="color: #0000cc">(</span>1<span style="color: #0000cc">)</span> <span style="color: #0000cc">{</span><br />conn_fd <span style="color: #0000cc">=</span> <span style="color: #ff0000">accept</span><span style="color: #0000cc">(</span>listen_fd<span style="color: #0000cc">,</span> <span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">)</span><span style="color: #0000cc">;</span><br />do_service<span style="color: #0000cc">(</span>conn_fd<span style="color: #0000cc">,</span> <span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">)</span><span style="color: #0000cc">;</span><br /><span style="color: #0000cc">}</span><br /></span></code></p></td></tr></tbody></table><br />初识上述代码，真有眼前一亮的感觉，也正如作者所说，以上代码确实很少见（反正我读此书之前是确实没见过）。作者真是构思精巧，巧妙地绕过了常见的预先创建 子进程的多进程服务器当主服务进程接收到新的连接必须想办法将这个连接传递给服务子进程的&#8220;陷阱&#8221;，上述代码通过共享的倾听套接字，由子进程主动地去向内 核&#8220;索要&#8221;连接套接字，从而避免了用UNIX域套接字传递文件描述符的&#8220;淫技&#8221;。<br /><br />不过，当接着往下读的时候，作者谈到了&#8220;惊群&#8221; （Thundering herd)问题。所谓的&#8220;惊群&#8221;就是，当很多进程都阻塞在accept系统调用的时候，即使只有一个新的连接达到，内核也会唤醒所有阻塞在accept上 的进程，这将给系统带来非常大的&#8220;震颤&#8221;，降低系统性能。<br /><br />除了这个问题，accept还必须是原子操作。为此，作者在接下来的27.7节讲述了加了互斥锁的版本：<br /><br />
<table style="border-collapse: collapse" cellspacing="0" cellpadding="0" width="95%" bgcolor="#f1f1f1" border="1">
<tbody>
<tr>
<td>
<p style="margin: 5px; line-height: 150%"><code><span style="color: #000000"><span style="color: #0000ff">while</span> <span style="color: #0000cc">(</span>1<span style="color: #0000cc">)</span> <span style="color: #0000cc">{</span><br />lock<span style="color: #0000cc">(</span><span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">)</span><span style="color: #0000cc">;</span><br />conn_fd <span style="color: #0000cc">=</span> <span style="color: #ff0000">accept</span><span style="color: #0000cc">(</span>listen_fd<span style="color: #0000cc">,</span> <span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">)</span><span style="color: #0000cc">;</span><br />unlock<span style="color: #0000cc">(</span><span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">)</span><span style="color: #0000cc">;</span><br />do_service<span style="color: #0000cc">(</span>conn_fd<span style="color: #0000cc">,</span> <span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">.</span><span style="color: #0000cc">)</span><span style="color: #0000cc">;</span><br /><span style="color: #0000cc">}</span><br /></span></code></p></td></tr></tbody></table><br />原子操作的问题算是解决了，那么&#8220;惊群&#8221;呢？文中只是提到在Solaris系统上当子进程数由75变成90后，CPU时间显著增加，并且作者认为这是因为进 程过多，导致内存互换。对&#8220;惊群&#8221;问题回答地十分含糊。通过比较书中图27.2的第4列和第7列的内容，我们可以肯定&#8220;真凶&#8221;绝对不是&#8220;内存对换&#8221;。<br /><br />&#8220;元凶&#8221;到底是谁？<br /><br />仔细分析一下，加锁真的有助于&#8220;惊群&#8221;问题么？不错，确实在同一时间只有一个子进程在调用accept，其它子进程都阻塞在了lock语句，但是，当 accept返回并unlock之后呢？unlock肯定是要唤醒阻塞在这个锁上的进程的，不过谁都没有规定是唤醒一个还是唤醒多个。所以，潜在的&#8220;惊 群&#8221;问题还是存在，只不过换了个地方，换了个形式。而造成Solaris性能骤降的&#8220;罪魁祸首&#8221;很有可能就是&#8220;惊群&#8221;问题。<br /><br />崩溃了！这么说所有的锁都有可能产生惊群问题了？<br /><br />似乎真的是这样，所以<span style="font-weight: bold">减少锁的使用</span>很重要。特别是在竞争比较激烈的地方。<br /><br />作者在27.9节所实现的&#8220;传递文件描述符&#8221;版本的服务器就有效地克服了&#8220;惊群&#8221;问题，在现实的服务器实现中，最常用的也是此节所提到的基于&#8220;分配&#8221;形式。<br /><br /><span style="font-weight: bold">把&#8220;竞争&#8221;换成&#8220;分配&#8221;</span>是避免&#8220;惊群&#8221;问题的有效方法，但是<span style="font-weight: bold">也不要忽视&#8220;分配&#8221;的&#8220;均衡&#8221;问题</span>，不然后果可能更加严重哦！</div></div><img src ="http://www.cppblog.com/mysileng/aggbug/207932.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2014-08-07 14:21 <a href="http://www.cppblog.com/mysileng/archive/2014/08/07/207932.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux系统调用</title><link>http://www.cppblog.com/mysileng/archive/2013/04/04/199091.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Thu, 04 Apr 2013 03:57:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2013/04/04/199091.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/199091.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2013/04/04/199091.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/199091.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/199091.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 目录：1. Linux系统调用原理2. 系统调用的实现3. Linux系统调用分类及列表4.系统调用、用户编程接口(API)、系统命令和内核函数的关系5. Linux系统调用实例6. Linux自定义系统调用1.系统调用原理系统调用，顾名思义，说的是操作系统提供给用户程序调用的一组&#8220;特殊&#8221;接口。用户程序可以通过这组&#8220;特殊&#8221;接口来获得操作系统内核提供的...&nbsp;&nbsp;<a href='http://www.cppblog.com/mysileng/archive/2013/04/04/199091.html'>阅读全文</a><img src ="http://www.cppblog.com/mysileng/aggbug/199091.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2013-04-04 11:57 <a href="http://www.cppblog.com/mysileng/archive/2013/04/04/199091.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux多线程中使用信号 (转)</title><link>http://www.cppblog.com/mysileng/archive/2013/01/18/197392.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Fri, 18 Jan 2013 08:52:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2013/01/18/197392.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/197392.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2013/01/18/197392.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/197392.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/197392.html</trackback:ping><description><![CDATA[<p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><span style="font-size: 13px;">&nbsp; &nbsp; &nbsp; &nbsp;在Linux的多线程中使用信号机制，与在进程中使用信号机制有着根本的区别，可以说是完全不同。在进程环境中，对信号的处理是，先注册信号处理函数，当信号异步发生时，调用处理函数来处理信号。它<span style="color: #800000;"><strong>完全是异步</strong></span>的（<span style="color: #000080;">我们完全不知到信号会在进程的那个执行点到来！</span>）。然而信号处理函数的实现，有着许多的限制；比如有一些函数不能在信号处理函数中调用；再比如一些函数read、recv等调用时会被异步的信号给中断(interrupt)，因此我们必须对在这些函数在调用时因为信号而中断的情况进行处理（判断函数返回时 enno 是否等于 EINTR）。</span></p><div style="background-color: #ffffff;"><span style="color: #333333; font-family: Arial; font-size: 13px; line-height: 26px;"><br /></span><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><span style="font-size: 13px;">&nbsp; &nbsp; &nbsp; &nbsp;但是在多线程中处理信号的原则却完全不同，它的基本原则是：<span style="color: #800000;">将对信号的异步处理，<strong>转换成同步处理</strong></span>，也就是说<span style="color: #000080;">用一个线程专门的来&#8220;同步等待&#8221;信号的到来</span>，而<span style="color: #000080;">其它的线程可以完全不被该信号中断/打断(interrupt)</span>。这样就在相当程度上简化了在多线程环境中对信号的处理。而且可以保证其它的线程不受信号的影响。这样<span style="color: #800000;">我们对信号就可以完全预测</span>，因为它不再是异步的，而是同步的</span><span style="font-size: 13px;">（<span style="color: #000080;">我们完全知道信号会在哪个线程中的哪个执行点到来而被处理！</span>）</span><span style="font-size: 13px;">。而同步的编程模式总是比异步的编程模式简单。其实多线程相比于多进程的其中一个优点就是：多线程可以将进程中异步的东西转换成同步的来处理。<br /><br /></span><strong style="color: #000080; font-size: 13px;">1. sigwait函数：</strong><span style="font-size: 13px;"><br /></span></div><font color="#333333" face="Arial"><span style="font-size: 14px; line-height: 26px;">sigwait等一个或者多个指定信号发生。<br /></span></font><span style="line-height: 26px;">&nbsp; &nbsp; 它所做的工作只有两个：第一，监听被阻塞的信号；第二，如果所监听的信号产生了，则将其从未决队列中移出来（这里实时信号和非实时信号又有区别，体现在取出的顺序</span><span style="line-height: 26px;">等，具体自己取网上查，这里不再详述）。</span>sigwait并不改变信号掩码的阻塞与非阻塞状态。<span style="line-height: 26px;"><br /></span><span style="line-height: 26px;">&nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;">在POSIX标准中，当进程收到信号时，如果是多线程的情况，我们是无法确定是哪一个线程处理这个信号。而sigwait是从进程中pending的信号中，取走指定的信号。这样的</span><span style="line-height: 26px;">话，如果要确保sigwait这个线程收到该信号，那么所有线程含主线程以及这个sigwait线程则必须block住这个信号，因为如果自己不阻塞就没有未决状态(阻塞状态)信号，别的所有线程不阻塞就有可能当信号过来时，被其他的线程处理掉。</span><span style="line-height: 26px;"><br /></span><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><span style="font-size: 13px;"><strong><span style="color: #000080;">记住：</span></strong></span></div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><span style="font-size: 13px;">&nbsp; &nbsp; &nbsp;在多线程代码中，总是使用sigwait或者sigwaitinfo或者sigtimedwait等函数来处理信号。</span></div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><span style="font-size: 13px;">&nbsp; &nbsp; &nbsp;而不是signal或者sigaction等函数。因为在一个线程中调用signal或者sigaction等函数会改变所以线程中的</span></div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px;"><span style="font-size: 13px;">&nbsp; &nbsp; &nbsp;信号处理</span><span style="font-size: 13px; background-color: highlight;">函数。而不是仅仅改变调用signal/sigaction的那个线程的信号处理函数。<br /><br /></span><div style="font-size: 14px;"><span style="font-size: 13px;"><strong><span style="color: #000080;">2. pthread_sigmask函数：</span></strong></span></div><div style="font-size: 14px;"><span style="font-size: 14px;">&nbsp; &nbsp;</span><span style="font-size: 13px;">每个线程均有自己的信号屏蔽集（信号掩码），可以使用pthread_sigmask函数来<span style="color: #800000;">屏蔽某个线程对某些信号的</span></span></div><div style="font-size: 14px;"><span style="font-size: 13px;"><span style="color: #800000;">&nbsp; &nbsp;响应处理</span>，仅留下需要</span><span style="font-size: 13px;">处理该信号的线程来处理指定的信号。实现方式是：利用线程信号屏蔽集的继承关系</span></div><div style="font-size: 14px;"><span style="font-size: 13px;">&nbsp; （</span><span style="font-size: 13px;">在主进程中对sigmask进行</span><span style="font-size: 13px;">设置后，主进程创建出来的线程将<span style="color: #800000;">继承主进程的掩码</span>）<br /><br /></span></div><div style="font-size: 14px;"><span style="font-size: 13px; color: #000080;"><strong>3. pthread_kill函数：</strong></span></div><div style="font-size: 14px;"><span style="font-size: 13px;">&nbsp; &nbsp;在多线程程序中，一个线程可以使用pthread_kill对同一个进程中指定的线程（包括自己）发送信号。注意在多线程中 &nbsp;</span></div><div style="font-size: 14px;"><span style="font-size: 13px;">&nbsp; 一般不使用kill函数发送信号，因为kill是对进程发送信号，结果是：正在运行的线程会处理该信号，如果该线程没有</span></div><div style="font-size: 14px;"><span style="font-size: 13px;">&nbsp;注册信号</span><span style="font-size: 13px;">处理</span><span style="font-size: 13px;">函数，那么会导致整个进程退出。</span></div><span style="font-size: 13px; color: #000080; font-weight: bold;">记住：</span><span style="font-size: 13px;">调用sigwait同步等待的信号必须在调用线程中被屏蔽，并且通常应该在所有的线程中被屏蔽（这样可以保证信号绝不会被送到除了调用sigwait的任何其它线程），这是通过利用信号掩码的继承关系来达到的。</span><span style="font-size: 13px;"><br /></span></div></div><img src ="http://www.cppblog.com/mysileng/aggbug/197392.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2013-01-18 16:52 <a href="http://www.cppblog.com/mysileng/archive/2013/01/18/197392.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>fcntl使用 (转)</title><link>http://www.cppblog.com/mysileng/archive/2013/01/15/197279.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Tue, 15 Jan 2013 02:57:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2013/01/15/197279.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/197279.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2013/01/15/197279.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/197279.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/197279.html</trackback:ping><description><![CDATA[<p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="color: #0000ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">功能描述：根据文件描述词来操作文件的特性。</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">#include&nbsp;&lt;unistd.h&gt;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">#include&nbsp;&lt;fcntl.h&gt;&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">int&nbsp;fcntl(int&nbsp;fd,&nbsp;int&nbsp;cmd);&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">int&nbsp;fcntl(int&nbsp;fd,&nbsp;int&nbsp;cmd,&nbsp;long&nbsp;arg);&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">int&nbsp;fcntl(int&nbsp;fd,&nbsp;int&nbsp;cmd,&nbsp;struct&nbsp;flock&nbsp;*lock);</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="color: #0000ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">[描述]</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">fcntl()针对(文件)描述符提供控制。参数fd是被参数cmd操作(如下面的描述)的描述符。针对cmd的值，fcntl能够接受第三个参数int&nbsp;arg。</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="color: #0000ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">[返回值]</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">fcntl()的返回值与命令有关。如果出错，所有命令都返回－1，如果成功则返回某个其他值。下列三个命令有特定返回值：F_DUPFD&nbsp;,&nbsp;F_GETFD&nbsp;,&nbsp;F_GETFL以及F_GETOWN。</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;F_DUPFD&nbsp;&nbsp;&nbsp;返回新的文件描述符</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;F_GETFD&nbsp;&nbsp;&nbsp;返回相应标志</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;F_GETFL&nbsp;,&nbsp;F_GETOWN&nbsp;&nbsp;&nbsp;返回一个正的进程ID或负的进程组ID</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; ">&nbsp;</p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="color: #0000ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">fcntl函数有5种功能：</span>&nbsp;<span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">1.&nbsp;复制一个现有的描述符(cmd=F_DUPFD).&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">2.&nbsp;获得／设置文件描述符标记(cmd=F_GETFD或F_SETFD).&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">3.&nbsp;获得／设置文件状态标记(cmd=F_GETFL或F_SETFL).&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">4.&nbsp;获得／设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN).&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">5.&nbsp;获得／设置记录锁(cmd=F_GETLK&nbsp;,&nbsp;F_SETLK或F_SETLKW).</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="color: #008000; font-weight: bold; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">1.&nbsp;cmd值的F_DUPFD&nbsp;：</span>&nbsp;<span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">F_DUPFD</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;返回一个如下描述的(文件)描述符：</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#183;最小的大于或等于arg的一个可用的描述符</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#183;与原始操作符一样的某对象的引用</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#183;如果对象是文件(file)的话，则返回一个新的描述符，这个描述符与arg共享相同的偏移量(offset)</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#183;相同的访问模式(读，写或读/写)</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#183;相同的文件状态标志(如：两个文件描述符共享相同的状态标志)</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#183;与新的文件描述符结合在一起的close-on-exec标志被设置成交叉式访问execve(2)的系统调用</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">实际上调用dup(oldfd)；</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">等效于</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;fcntl(oldfd,&nbsp;F_DUPFD,&nbsp;0);</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">而调用dup2(oldfd,&nbsp;newfd)；</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">等效于</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;close(oldfd)；</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fcntl(oldfd,&nbsp;F_DUPFD,&nbsp;newfd)；</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="color: #008000; font-weight: bold; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">2.&nbsp;cmd值的F_GETFD和F_SETFD：</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">F_GETFD</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;取得与文件描述符fd联合的close-on-exec标志，类似FD_CLOEXEC。如果返回值和FD_CLOEXEC进行与运算结果是0的话，文件保持交叉式访问exec()，否则如果通过exec运行的话，文件将被关闭(arg&nbsp;被忽略)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">F_SETFD</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;设置close-on-exec标志，该标志以参数arg的FD_CLOEXEC位决定，应当了解很多现存的涉及文件描述符标志的程序并不使用常数&nbsp;FD_CLOEXEC，而是将此标志设置为0(系统默认，在exec时不关闭)或1(在exec时关闭)&nbsp;&nbsp;&nbsp;&nbsp;</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="color: #0000ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">在修改文件描述符标志或文件状态标志时必须谨慎，先要取得现在的标志值，然后按照希望修改它，最后设置新标志值。不能只是执行F_SETFD或F_SETFL命令，这样会关闭以前设置的标志位。</span>&nbsp;</p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="color: #008000; font-weight: bold; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">3.&nbsp;cmd值的F_GETFL和F_SETFL：</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">F_GETFL</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;取得fd的文件状态标志，如同下面的描述一样(arg被忽略)，在说明open函数时，已说明</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">了文件状态标志。不幸的是，三个存取方式标志&nbsp;(O_RDONLY&nbsp;,&nbsp;O_WRONLY&nbsp;,&nbsp;以及O_RDWR)并不各占1位。(这三种标志的值各是0&nbsp;,&nbsp;1和2，由于历史原因，这三种值互斥&nbsp;&#8212;&nbsp;一个文件只能有这三种值之一。)&nbsp;因此首先</span><span style="color: #00ccff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">必须用屏蔽字O_ACCMODE相与取得存取方式位</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">，然后将结果与这三种值相比较。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">F_SETFL</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;设置给arg描述符状态标志，可以更改的几个标志是：O_APPEND，O_NONBLOCK，O_SYNC&nbsp;和&nbsp;O_ASYNC。</span><span style="color: #00ccff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">而fcntl的文件状态标志总共有7个：O_RDONLY&nbsp;,&nbsp;O_WRONLY&nbsp;,&nbsp;O_RDWR&nbsp;,&nbsp;O_APPEND&nbsp;,&nbsp;O_NONBLOCK&nbsp;,&nbsp;O_SYNC和O_ASYNC</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="color: #0000ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">可更改的几个标志如下面的描述：</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;O_NONBLOCK</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;非阻塞I/O，如果read(2)调用没有可读取的数据，或者如果write(2)操作将阻塞，则read或write调用将返回-1和EAGAIN错误</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;O_APPEND</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;强制每次写(write)操作都添加在文件大的末尾，相当于open(2)的O_APPEND标志</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;O_DIRECT</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;最小化或去掉reading和writing的缓存影响。系统将企图避免缓存你的读或写的数据。如果不能够避免缓存，那么它将最小化已经被缓存了的数据造成的影响。如果这个标志用的不够好，将大大的降低性能</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;O_ASYNC</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当I/O可用的时候，允许SIGIO信号发送到进程组，例如：当有数据可以读的时候<br /></span></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->转载自：http:<span style="color: #008000; ">//</span><span style="color: #008000; ">blog.163.com/xychenbaihu@yeah/blog/static/132229655201010265577965/</span><span style="color: #008000; "><br /></span>1、获取文件的flags，即open函数的第二个参数:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flags&nbsp;=&nbsp;fcntl(fd,F_GETFL,0);<br /><br />2、设置文件的flags:<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fcntl(fd,F_SETFL,flags);<br /><br />3、增加文件的某个flags，比如文件是阻塞的，想设置成&nbsp;非阻塞:<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flags&nbsp;=&nbsp;fcntl(fd,F_GETFL,0);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flags&nbsp;|=&nbsp;O_NONBLOCK;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fcntl(fd,F_SETFL,flags);<br /><br />4、取消文件的某个flags，比如文件是非阻塞的，想设置&nbsp;成为阻塞:<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flags&nbsp;=&nbsp;fcntl(fd,F_GETFL,0);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flags&nbsp;&amp;=&nbsp;~O_NONBLOCK;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fcntl(fd,F_SETFL,flags);<br /><br />&nbsp;<br /><br />获取和设置文件flags举例::<br /><br />#include&nbsp;&lt;stdio.h&gt;<br />#include&nbsp;&lt;stdlib.h&gt;<br />#include&nbsp;&lt;unistd.h&gt;<br />#include&nbsp;&lt;fcntl.h&gt;<br />#include&nbsp;&lt;error.h&gt;<br /><br /><span style="color: #0000FF; ">char</span>&nbsp;buf[500000];<br /><br /><span style="color: #0000FF; ">int</span>&nbsp;main(<span style="color: #0000FF; ">int</span>&nbsp;argc,<span style="color: #0000FF; ">char</span>&nbsp;*argv[])<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;ntowrite,nwrite;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">const</span>&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;*ptr&nbsp;;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;flags;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ntowrite&nbsp;=&nbsp;read(STDIN_FILENO,buf,<span style="color: #0000FF; ">sizeof</span>(buf));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(ntowrite&nbsp;&lt;0)&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;perror("read&nbsp;STDIN_FILENO&nbsp;fail:");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,"read&nbsp;%d&nbsp;bytes\n",ntowrite);<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>((flags&nbsp;=&nbsp;fcntl(STDOUT_FILENO,F_GETFL,0))==-1)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;perror("fcntl&nbsp;F_GETFL&nbsp;fail:");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flags&nbsp;|=&nbsp;O_NONBLOCK;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(fcntl(STDOUT_FILENO,F_SETFL,flags)==-1)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;perror("fcntl&nbsp;F_SETFL&nbsp;fail:");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ptr&nbsp;=&nbsp;buf;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>(ntowrite&nbsp;&gt;&nbsp;0)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nwrite&nbsp;=&nbsp;write(STDOUT_FILENO,ptr,ntowrite);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(nwrite&nbsp;==&nbsp;-1)&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;perror("write&nbsp;file&nbsp;fail:");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(nwrite&nbsp;&gt;&nbsp;0)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ptr&nbsp;+=&nbsp;nwrite;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ntowrite&nbsp;-=&nbsp;nwrite;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flags&nbsp;&amp;=&nbsp;~O_NONBLOCK;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(fcntl(STDOUT_FILENO,F_SETFL,flags)==-1)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;perror("fcntl&nbsp;F_SETFL&nbsp;fail2:");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />}</div><p>&nbsp;</p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="color: #008000; font-weight: bold; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">4.&nbsp;cmd值的F_GETOWN和F_SETOWN：</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">F_GETOWN</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;取得当前正在接收SIGIO或者SIGURG信号的进程id或进程组id，进程组id返回的是负值(arg被忽略)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">F_SETOWN</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;设置将接收SIGIO和SIGURG信号的进程id或进程组id，进程组id通过提供负值的arg来说明(arg绝对值的一个进程组ID)，否则arg将被认为是进程id</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="color: #008000; font-weight: bold; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;5.&nbsp;cmd值的F_GETLK,&nbsp;F_SETLK或F_SETLKW：</span>&nbsp;<span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">获得／设置记录锁的功能，成功则返回0，若有错误则返回-1，错误原因存于errno。</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">F_GETLK</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;通过第三个参数arg(一个指向flock的结构体)取得第一个阻塞lock&nbsp;description指向的锁。取得的信息将覆盖传到fcntl()的flock结构的信息。如果没有发现能够阻止本次锁(flock)生成的锁，这个结构将不被改变，除非锁的类型被设置成F_UNLCK&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">F_SETLK</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;&nbsp;按照指向结构体flock的指针的第三个参数arg所描述的锁的信息设置或者清除一个文件的segment锁。F_SETLK被用来实现共享(或读)锁(F_RDLCK)或独占(写)锁(F_WRLCK)，同样可以去掉这两种锁(F_UNLCK)。如果共享锁或独占锁不能被设置，fcntl()将立即返回EAGAIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">F_SETLKW</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">&nbsp;&nbsp;&nbsp;除了共享锁或独占锁被其他的锁阻塞这种情况外，这个命令和F_SETLK是一样的。如果共享锁或独占锁被其他的锁阻塞，进程将等待直到这个请求能够完成。当fcntl()正在等待文件的某个区域的时候捕捉到一个信号，如果这个信号没有被指定SA_RESTART,&nbsp;fcntl将被中断</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">当一个共享锁被set到一个文件的某段的时候，其他的进程可以set共享锁到这个段或这个段的一部分。共享锁阻止任何其他进程set独占锁到这段保护区域的任何部分。如果文件描述符没有以读的访问方式打开的话，共享锁的设置请求会失败。</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">独占锁阻止任何其他的进程在这段保护区域任何位置设置共享锁或独占锁。如果文件描述符不是以写的访问方式打开的话，独占锁的请求会失败。</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="color: #0000ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">结构体flock的指针：</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">struct&nbsp;flcok&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">{&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">short&nbsp;int&nbsp;l_type;&nbsp;/*&nbsp;锁定的状态*/</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">//以下的三个参数用于分段对文件加锁，若对整个文件加锁，则：l_whence=SEEK_SET,&nbsp;l_start=0,&nbsp;l_len=0</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">short&nbsp;int&nbsp;l_whence;&nbsp;/*决定l_start位置*/&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">off_t&nbsp;l_start;&nbsp;/*锁定区域的开头位置*/&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">off_t&nbsp;l_len;&nbsp;/*锁定区域的大小*/</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">pid_t&nbsp;l_pid;&nbsp;/*锁定动作的进程*/&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">};</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">l_type&nbsp;有三种状态：</span>&nbsp;<span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">F_RDLCK&nbsp;&nbsp;&nbsp;建立一个供读取用的锁定&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">F_WRLCK&nbsp;&nbsp;&nbsp;建立一个供写入用的锁定&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">F_UNLCK&nbsp;&nbsp;&nbsp;删除之前建立的锁定</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">l_whence&nbsp;也有三种方式：</span>&nbsp;<span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">SEEK_SET&nbsp;&nbsp;&nbsp;以文件开头为锁定的起始位置&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">SEEK_CUR&nbsp;&nbsp;&nbsp;以目前文件读写位置为锁定的起始位置&nbsp;</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">SEEK_END&nbsp;&nbsp;&nbsp;以文件结尾为锁定的起始位置</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="color: #0000ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">fcntl文件锁有两种类型：建议性锁和强制性锁</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">建议性锁是这样规定的</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">：每个使用上锁文件的进程都要检查是否有锁存在，当然还得尊重已有的锁。内核和系统总体上都坚持不使用建议性锁，它们依靠程序员遵守这个规定。</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">强制性锁是由内核执行的</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">：当文件被上锁来进行写入操作时，在锁定该文件的进程释放该锁之前，内核会阻止任何对该文件的读或写访问，每次读或写访问都得检查锁是否存在。</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">系统默认fcntl都是建议性锁，强制性锁是非POSIX标准的。</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">如果要使用强制性锁，要使整个系统可以使用强制性锁，那么得需要重新挂载文件系统，mount使用参数&nbsp;-0&nbsp;mand&nbsp;打开强制性锁，或者关闭已加锁文件的组执行权限并且打开该文件的set-GID权限位。</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">建议性锁只在cooperating&nbsp;processes之间才有用</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">。对cooperating&nbsp;process的理解是最重要的，它指的是会影响其它进程的进程或被别的进程所影响的进程，</span><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">举两个例子：</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">(1)&nbsp;我们可以同时在两个窗口中运行同一个命令，对同一个文件进行操作，那么这两个进程就是cooperating&nbsp;&nbsp;processes</span><span style="font-size: 9.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;"><br /></span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">(2)&nbsp;cat&nbsp;file&nbsp;|&nbsp;sort，那么cat和sort产生的进程就是使用了pipe的cooperating&nbsp;processes</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="color: #0000ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">使用fcntl文件锁进行I/O操作必须小心：</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">进程在开始任何I/O操作前如何去处理锁，在对文件解锁前如何完成所有的操作，是必须考虑的。如果在设置锁之前打开文件，或者读取该锁之后关闭文件，另一个进程就可能在上锁/解锁操作和打开/关闭操作之间的几分之一秒内访问该文件。当一个进程对文件加锁后，无论它是否释放所加的锁，只要文件关闭，内核都会自动释放加在文件上的建议性锁(这也是建议性锁和强制性锁的最大区别)，所以不要想设置建议性锁来达到永久不让别的进程访问文件的目的(强制性锁才可以)；强制性锁则对所有进程起作用。</span></p><p style="margin-bottom:7.5000pt; margin-top:0pt; text-autospace:ideograph-other; line-height:16.5000pt; background:#ffffff; "><span style="color: #0000ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">fcntl使用三个参数&nbsp;F_SETLK/F_SETLKW，&nbsp;F_UNLCK和F_GETLK&nbsp;来分别要求、释放、测试record&nbsp;locks</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">。record&nbsp;locks是对文件一部分而不是整个文件的锁，这种细致的控制使得进程更好地协作以共享文件资源。fcntl能够用于读取锁和写入锁，</span><span style="color: #3366ff; font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">read&nbsp;lock也叫shared&nbsp;lock(共享锁)，&nbsp;因为多个cooperating&nbsp;process能够在文件的同一部分建立读取锁；write&nbsp;lock被称为exclusive&nbsp;lock(排斥锁)，因为任何时刻只能有一个cooperating&nbsp;process在文件的某部分上建立写入锁。</span><span style="font-size: 12.5pt; font-family: Verdana; background-position: initial initial; background-repeat: initial initial;">如果cooperating&nbsp;processes对文件进行操作，那么它们可以同时对文件加read&nbsp;lock，在一个cooperating&nbsp;process加write&nbsp;lock之前，必须释放别的cooperating&nbsp;process加在该文件的read&nbsp;lock和wrtie&nbsp;lock，也就是说，对于文件只能有一个write&nbsp;lock存在，read&nbsp;lock和wrtie&nbsp;lock不能共存。</span></p><img src ="http://www.cppblog.com/mysileng/aggbug/197279.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2013-01-15 10:57 <a href="http://www.cppblog.com/mysileng/archive/2013/01/15/197279.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux下网络IP地址的转换函数 (转)</title><link>http://www.cppblog.com/mysileng/archive/2013/01/09/197156.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Wed, 09 Jan 2013 10:02:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2013/01/09/197156.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/197156.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2013/01/09/197156.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/197156.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/197156.html</trackback:ping><description><![CDATA[<p style="color: #333333; font-family: tahoma, 宋体; font-size: 14px; line-height: 22px; background-color: #efefef;"><span style="font-size: 18px;">网络IP地址本是用32位二进制来表示的，为了记忆的方便可以用点分十进制来表示IP地址，同时，网络IP地址在网络传输和计算机内部的存储方式也不同，需要用函数来进行转换。</span>&nbsp;</p><p style="color: #333333; font-family: tahoma, 宋体; font-size: 14px; line-height: 22px; background-color: #efefef;"><span style="font-size: 18px;">1.将<span style="color: #ff0000;">点分十进制字符串转换成十进制长整型数</span>：in_addr_t inet_addr(const char *cp);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in_addr_t 即long型，参数cp表示一个点分十进制字符串，返回值是十进制长整型数。</span>&nbsp;<br /><br /></p><p style="color: #333333; font-family: tahoma, 宋体; font-size: 14px; line-height: 22px; background-color: #efefef;"><span style="font-size: 18px;">2.将<span style="color: #ff0000;">长整型IP地址转换成点分十进制</span>：char *inet_ntoa(struct in_addr in);&nbsp;&nbsp; 参数in是一个in_addr类型的结构体，这个结构体在man 7 ip中查得到：<br />&nbsp; struct in_addr{<br />&nbsp; &nbsp; &nbsp;uint32_t s_addr<br />&nbsp; };<br />inet_ntoa返回的是点分十进制的IP地址字符串。</span>&nbsp;<br /><br /></p><p name="code" style="color: #333333; font-family: tahoma, 宋体; font-size: 14px; line-height: 22px; background-color: #efefef;"><span style="font-size: 18px;">3.<span style="color: #ff0000;">主机字符顺序和网络字符顺序的转换</span>：计算机中的字符和网络中的字符的存储顺序是不同的，计算机中的整型数和网络中的整型数进行交换时，需要相关的函数进行转换。如果将计算机中的长整型IP地址转换成网络字符顺序的整型IP地址，使用htonl函数。这些函数如下：</span></p><p name="code" style="color: #333333; font-family: tahoma, 宋体; font-size: 14px; line-height: 22px; background-color: #efefef;"><span style="font-size: 18px;">uint32_t htonl(uint32_t hostlong);将计算机中的32位长整型数转换成网络字符顺序的32位长整型数。</span><span style="font-size: 18px; color: red;">(用于IP的转换)</span></p><p name="code" style="color: #333333; font-family: tahoma, 宋体; font-size: 14px; line-height: 22px; background-color: #efefef;"><span style="font-size: 18px;">uint16_t htons(uint16_t hostshort);将计算机中的16位整型数转换成网络字符顺序的16位整型数。。</span><span style="font-size: 18px; color: red;">(用于port的转换)</span></p><p name="code" style="color: #333333; font-family: tahoma, 宋体; font-size: 14px; line-height: 22px; background-color: #efefef;"><span style="font-size: 18px;">uint32_t ntohl(uint32_t netlong);将网络中的32位常整型数转换成计算机中的32位长整型数。。(用于IP的转换)</span></p><p name="code" style="color: #333333; font-family: tahoma, 宋体; font-size: 14px; line-height: 22px; background-color: #efefef;"><span style="font-size: 18px;">uint16_t ntons(uint16_t netshort);将网络中的16位整型数转换成计算机中的16位整型数。。(用于port的转换)<br /><br />转自:</span>http://www.linuxidc.com/Linux/2012-01/51068.htm</p><img src ="http://www.cppblog.com/mysileng/aggbug/197156.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2013-01-09 18:02 <a href="http://www.cppblog.com/mysileng/archive/2013/01/09/197156.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>shmdt与shmctl的区别</title><link>http://www.cppblog.com/mysileng/archive/2013/01/06/197013.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Sun, 06 Jan 2013 05:08:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2013/01/06/197013.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/197013.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2013/01/06/197013.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/197013.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/197013.html</trackback:ping><description><![CDATA[<p align="left" style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><span style="font-size: 14px;">先看看 shmctl()&nbsp;</span></p><p align="left" style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;原型：&nbsp;int&nbsp;shmctl ( int shmqid, int cmd, struct shmid_ds *buf );</p><p align="left" style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;返回：成功为&nbsp;0&nbsp;，&nbsp;&nbsp;&nbsp;失败 为-1</p><p align="left" style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;</p><p align="left" style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">这个特殊的调用和semctl()调用几乎相同，因此，这里不进行详细的讨论。有效命令的值是：&nbsp;</p><p align="left" style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">IPC_STAT&nbsp;：检索一个共享段的shmid_ds结构，把它存到buf参数的地址中。&nbsp;</p><p align="left" style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">IPC_SET&nbsp;：对一个共享段来说，从buf&nbsp;参数中取值设置shmid_ds结构的ipc_perm域的值。&nbsp;</p><p align="left" style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">IPC_RMID&nbsp;：把一个段标记为删除&nbsp;</p><p align="left" style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><br /></p><p align="left" style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><span style="color: #ff0000;">&nbsp;IPC_RMID&nbsp;命令实际上不从内核删除一个段，而是仅仅把这个段标记为删除，实际的删除发生在最后一个进程离开这个共享段时。</span></p><p align="left" style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><span style="color: #ff0000;">当一个进程不再需要共享内存段时，它将调用shmdt()系统调用卸载，即本进程不再使用这个段，但是，这并不是从内核真正地删除这个段，而是把相关shmid_ds结构的&nbsp;shm_nattch域的值减1。真正把内核中的共享内存删除还得用shmctl。</span></p><img src ="http://www.cppblog.com/mysileng/aggbug/197013.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2013-01-06 13:08 <a href="http://www.cppblog.com/mysileng/archive/2013/01/06/197013.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>mmap详解(转)</title><link>http://www.cppblog.com/mysileng/archive/2013/01/06/197006.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Sun, 06 Jan 2013 02:37:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2013/01/06/197006.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/197006.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2013/01/06/197006.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/197006.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/197006.html</trackback:ping><description><![CDATA[<p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; font-size: 14px; line-height: 21px; background-color: #ffffff;">mmap函数是unix/linux下的系统调用。</p><p style="margin: 0px; padding: 0px; color: #454545; font-family: tahoma, helvetica, arial; font-size: 14px; line-height: 21px; background-color: #ffffff;">mmap系统调用并不是完全为了用于共享内存而设计的。它本身提供了不同于一般对普通文件的访问方式，进程可以像读写内存一样对普通文件的操作。而Posix或系统V的共享内存IPC则纯粹用于共享目的，当然mmap()实现共享内存也是其主要应用之一。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mmap系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后，进程可以像访问普通内存一样对文件进行访问，不必再调用read()，write（）等操作。<span style="color: red;">mmap并不分配空间, 只是将文件映射到调用进程的地址空间里(因为并不分配空间所以所映射的文件必须已经具有大小，空文件会产生错误)</span>, 然后你就可以用memcpy等操作写文件, 而不用write()了.写完后用msync()同步一下, 你所写的内容就保存到文件里了. 不过这种方式没办法增加文件的长度, 因为要映射的长度在调用mmap()的时候就决定了.<br /><br /></p><img src ="http://www.cppblog.com/mysileng/aggbug/197006.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2013-01-06 10:37 <a href="http://www.cppblog.com/mysileng/archive/2013/01/06/197006.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>signal/kill 与 sigaction/sigqueue</title><link>http://www.cppblog.com/mysileng/archive/2013/01/05/196983.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Sat, 05 Jan 2013 09:19:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2013/01/05/196983.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196983.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2013/01/05/196983.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196983.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196983.html</trackback:ping><description><![CDATA[<div>sigaction/sigqueue是signal/kill的升级版<br /><br />1.sigqueue与kill:sigqueue可以发送额外参数，kill不可以.<br /><br />2.sigaction与signal:signal通过sigaction实现,sigaction除与signal一样会屏蔽正在处理的信号，还可以通过指定sa_mask屏蔽指定信号。<br /><br />3.sigaction与signal: sigaction还可以传送信号相关的更多信息及参数.<br /><br />4.上述4个函数可以混合使用.</div><img src ="http://www.cppblog.com/mysileng/aggbug/196983.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2013-01-05 17:19 <a href="http://www.cppblog.com/mysileng/archive/2013/01/05/196983.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>信号可靠、不可靠的原因 (转)</title><link>http://www.cppblog.com/mysileng/archive/2013/01/05/196965.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Sat, 05 Jan 2013 03:45:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2013/01/05/196965.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196965.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2013/01/05/196965.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196965.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196965.html</trackback:ping><description><![CDATA[<p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">原文地址：<a href="http://blogold.chinaunix.net/u1/48788/showart.php?id=2270724" style="color: #336699; text-decoration: initial;">http://blogold.chinaunix.net/u1/48788/showart.php?id=2270724</a></p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"></p><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">早期的信号，也就是前32位的信号，在处理信号时，不具备阻塞该信号的能力（也就是不支持排队），只能忽略，这时候就可能丢失信号。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">使用不可靠信号时注意：</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><span style="font-size: 13px;"><span style="font-family: 宋体;"><span style="background-color: #0d0d0d;"><span style="color: #ffa0a0;">1)</span></span>&nbsp;不要在中断函数中执行过于复杂的处理流程；<br style="font-size: 12px; line-height: normal; font-family: song, Verdana;" /></span></span><span style="font-size: 13px;"><span style="font-family: 宋体;"><span style="background-color: #0d0d0d;"><span style="color: #ffa0a0;">2)</span></span>&nbsp;在信号处理过程返回前，进程会对相同信号的标志进行屏蔽；<br style="font-size: 12px; line-height: normal; font-family: song, Verdana;" /></span><span style="font-family: 宋体;"><span style="background-color: #0d0d0d;"><span style="color: #ffa0a0;">3)</span></span>&nbsp;父进程会把当前的信号屏蔽标志位信息传递给它派生的子进程。</span></span></div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><a name="1" style="color: #336699;">一、信号及信号来源</a></div><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"></p><p style="color: #333333; background-color: #ffffff; font-size: 12px; line-height: normal; font-family: song, Verdana;"><strong>信号本质</strong></p><p style="color: #333333; background-color: #ffffff; font-size: 12px; line-height: normal; font-family: song, Verdana;">信号是在软件层次上对中断机制的一种模拟，在原理上，一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是异步的，一个进程不必通过任何操作来等待信号的到达，事实上，进程也不知道信号到底什么时候到达。</p><p style="color: #333333; background-color: #ffffff; font-size: 12px; line-height: normal; font-family: song, Verdana;">信号是进程间通信机制中唯一的异步通信机制，可以看作是异步通知，通知接收信号的进程有哪些事情发生了。信号机制经过POSIX实时扩展后，功能更加强大，除了基本通知功能外，还可以传递附加信息。</p><p style="color: #333333; background-color: #ffffff; font-size: 12px; line-height: normal; font-family: song, Verdana;"><strong>信号来源</strong></p><p style="color: #333333; background-color: #ffffff; font-size: 12px; line-height: normal; font-family: song, Verdana;">信号事件的发生有两个来源：硬件来源(比如我们按下了键盘或者其它硬件故障)；软件来源，最常用发送信号的系统函数是kill, raise, alarm和setitimer以及sigqueue函数，软件来源还包括一些非法运算等操作。</p><p style="color: #333333; background-color: #ffffff; font-size: 12px; line-height: normal; font-family: song, Verdana;"><a name="2" style="color: #336699;">二、信号的种类</a></p><p style="color: #333333; background-color: #ffffff; font-size: 12px; line-height: normal; font-family: song, Verdana;">可以从两个不同的分类角度对信号进行分类：（1）可靠性方面：可靠信号与不可靠信号；（2）与时间的关系上：实时信号与非实时信号。在《Linux环境进程间通信（一）：管道及有名管道》的附1中列出了系统所支持的所有信号。</p><p style="color: #333333; background-color: #ffffff; font-size: 12px; line-height: normal; font-family: song, Verdana;"><span twffan="done">1、可靠信号与不可靠信号</span></p><p style="color: #333333; background-color: #ffffff; font-size: 12px; line-height: normal; font-family: song, Verdana;"><strong>"不可靠信号"</strong></p><p style="color: #333333; background-color: #ffffff; font-size: 12px; line-height: normal; font-family: song, Verdana;">Linux信号机制基本上是从Unix系统中继承过来的。早期Unix系统中的信号机制比较简单和原始，后来在实践中暴露出一些问题，因此，把那些建立在早期机制上的信号叫做"不可靠信号"，信号值小于SIGRTMIN(Red hat 7.2中，SIGRTMIN=32，SIGRTMAX=63)的信号都是不可靠信号。这就是"不可靠信号"的来源。它的主要问题是：</p><ul style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><li>进程每次处理信号后，就将对信号的响应设置为默认动作。在某些情况下，将导致对信号的错误处理；因此，用户如果不希望这样的操作，那么就要在信号处理函数结尾再一次调用signal()，重新安装该信号。</li><li>信号可能丢失，后面将对此详细阐述。<br style="font-size: 12px; line-height: normal; font-family: song, Verdana;" />因此，早期unix下的不可靠信号主要指的是进程可能对信号做出错误的反应以及信号可能丢失。</li></ul><p style="color: #333333; background-color: #ffffff; font-size: 12px; line-height: normal; font-family: song, Verdana;">Linux支持不可靠信号，但是对不可靠信号机制做了改进：在调用完信号处理函数后，不必重新调用该信号的安装函数（信号安装函数是在可靠机制上的实现）。因此，Linux下的不可靠信号问题主要指的是信号可能丢失。</p><p style="color: #333333; background-color: #ffffff; font-size: 12px; line-height: normal; font-family: song, Verdana;"><strong>"可靠信号"</strong></p><p style="color: #333333; background-color: #ffffff; font-size: 12px; line-height: normal; font-family: song, Verdana;">随着时间的发展，实践证明了有必要对信号的原始机制加以改进和扩充。所以，后来出现的各种Unix版本分别在这方面进行了研究，力图实现"可靠信号"。由于原来定义的信号已有许多应用，不好再做改动，最终只好又新增加了一些信号，并在一开始就把它们定义为可靠信号，这些信号支持排队，不会丢失。同时，信号的发送和安装也出现了新版本：信号发送函数sigqueue()及信号安装函数sigaction()。POSIX.4对可靠信号机制做了标准化。但是，POSIX只对可靠信号机制应具有的功能以及信号机制的对外接口做了标准化，对信号机制的实现没有作具体的规定。</p><p style="color: #333333; background-color: #ffffff; font-size: 12px; line-height: normal; font-family: song, Verdana;"><span style="color: red;">信号值位于SIGRTMIN和SIGRTMAX之间的信号都是可靠信号</span>，可靠信号克服了信号可能丢失的问题。Linux在支持新版本的信号安装函数sigation（）以及信号发送函数sigqueue()的同时，仍然支持早期的signal（）信号安装函数，支持信号发送函数kill()。</p><p style="color: #333333; background-color: #ffffff; font-size: 12px; line-height: normal; font-family: song, Verdana;">注：不要有这样的误解：由sigqueue()发送、sigaction安装的信号就是可靠的。事实上，可靠信号是指后来添加的新信号（信号值位于SIGRTMIN及SIGRTMAX之间）；不可靠信号是信号值小于SIGRTMIN的信号。<span style="color: red;">信号的可靠与不可靠只与信号值有关，与信号的发送及安装函数无关</span>。目前linux中的signal()是通过sigation()函数实现的，因此，即使通过signal（）安装的信号，在信号处理函数的结尾也不必再调用一次信号安装函数。同时，由signal()安装的实时信号支持排队，同样不会丢失。</p><p style="color: #333333; background-color: #ffffff; font-size: 12px; line-height: normal; font-family: song, Verdana;">对于目前linux的两个信号安装函数:signal()及sigaction()来说，它们都不能把SIGRTMIN以前的信号变成可靠信号（都不支持排队，仍有可能丢失，仍然是不可靠信号），而且对SIGRTMIN以后的信号都支持排队。<span style="color: red;">这两个函数的最大区别在于，经过sigaction安装的信号都能传递信息给信号处理函数</span>（对所有信号这一点都成立），而经过signal安装的信号却不能向信号处理函数传递信息。对于信号发送函数来说也是一样的。</p><p style="color: #333333; background-color: #ffffff; font-size: 12px; line-height: normal; font-family: song, Verdana;"><span twffan="done">2、实时信号与非实时信号</span></p><p style="color: #333333; background-color: #ffffff; font-size: 12px; line-height: normal; font-family: song, Verdana;">早期Unix系统只定义了32种信号，Ret hat7.2支持64种信号，编号0-63(SIGRTMIN=31，SIGRTMAX=63)，将来可能进一步增加，这需要得到内核的支持。前32种信号已经有了预定义值，每个信号有了确定的用途及含义，并且每种信号都有各自的缺省动作。如按键盘的CTRL ^C时，会产生SIGINT信号，对该信号的默认反应就是进程终止。后32个信号表示实时信号，等同于前面阐述的可靠信号。这保证了发送的多个实时信号都被接收。实时信号是POSIX标准的一部分，可用于应用进程。</p><p style="color: #333333; background-color: #ffffff; font-size: 12px; line-height: normal; font-family: song, Verdana;">非实时信号都不支持排队，都是不可靠信号；实时信号都支持排队，都是可靠信号。</p><img src ="http://www.cppblog.com/mysileng/aggbug/196965.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2013-01-05 11:45 <a href="http://www.cppblog.com/mysileng/archive/2013/01/05/196965.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>scandir 函数 </title><link>http://www.cppblog.com/mysileng/archive/2013/01/02/196904.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Wed, 02 Jan 2013 03:48:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2013/01/02/196904.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196904.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2013/01/02/196904.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196904.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196904.html</trackback:ping><description><![CDATA[<div style="word-wrap: break-word; margin: 0px; line-height: 1.5; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8;">首先看一下man的scandir 接口定义</div><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8;"><table align="center" style="word-wrap: break-word; border-style: solid; border-color: #999999; font-size: 12px; width: 755px;"><tbody style="word-wrap: break-word;"><tr style="word-wrap: break-word; font-family: song, Verdana;"><td style="word-wrap: break-word;">int scandir(const char *dir, struct dirent ***namelist,<br style="word-wrap: break-word;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int(*filter)(const struct dirent *),<br style="word-wrap: break-word;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int(*compar)(const struct dirent **, const struct dirent **));<br style="word-wrap: break-word;" /></td></tr></tbody></table>,从定义来看就不是一个简单的函数，形参里，出现一个三级指针，二个函数指针。它的功能是，扫描名字为dir的目录，把满足filter函数的过滤条件（即filter执行为非0值）的目录项加入到一维指针数组namelist.数组的总长度为返回值n,如果compar不为空，则最终输出结果还要调用qsort来对数组进行排序后再输出。</div><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8;">&nbsp;</div><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8;">从scandir的演示代码，我们可以<span style="color: red;">推算出namelist是一个指向一维指针数组的指针。（一维指针数组等同于 struct dirent ** namelist,这里写在三级指针是因为要从函数里改变namelist的值，必须再多做一级）</span>原因可以参考我的函数传值类型的说明。</div><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8;">&nbsp;</div><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8;">以下是一个简单扫描 /usr/lib，并且把所有以lib打头的文件扫描到namelist数组的测试程序,这是参考scandir 提供的样例来修改,alphasort是做原始的ASCII码值比较进行排序的</div><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8;">&nbsp;</div><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8;">可以看到namelist是完全动态分配的，不仅数组本身是动态分配，而且数组项指向的空间也是动态分配的。</div><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8;">&nbsp;</div><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8;">&nbsp;</div><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8;"></div><table bordercolor="#999999" cellspacing="0" cellpadding="0" width="95%" bgcolor="#f1f1f1" border="1" style="word-wrap: break-word; color: #000000; font-family: 宋体, Arial; font-size: 12px; line-height: 15px; text-align: start; border-collapse: collapse;"><tbody style="word-wrap: break-word;"><tr style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;"><td style="word-wrap: break-word;"><p style="word-wrap: break-word; margin-right: 5px; margin-left: 5px; padding: 5px 0px 0px; line-height: 18px;"><code style="word-wrap: break-word;"><span style="word-wrap: break-word; line-height: 1.5;"><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">#</span><span style="word-wrap: break-word; line-height: 1.5; color: #ff0000;">include</span>&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&lt;</span>sys<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">/</span>types<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">.</span>h<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&gt;</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">#</span><span style="word-wrap: break-word; line-height: 1.5; color: #ff0000;">include</span>&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&lt;</span>dirent<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">.</span>h<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&gt;</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">#</span><span style="word-wrap: break-word; line-height: 1.5; color: #ff0000;">include</span>&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&lt;</span>sys<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">/</span>stat<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">.</span>h<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&gt;</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">#</span><span style="word-wrap: break-word; line-height: 1.5; color: #ff0000;">include</span>&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&lt;</span>unistd<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">.</span>h<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&gt;</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">#</span><span style="word-wrap: break-word; line-height: 1.5; color: #ff0000;">include</span>&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&lt;</span>stdio<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">.</span>h<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&gt;</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">#</span><span style="word-wrap: break-word; line-height: 1.5; color: #ff0000;">include</span>&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&lt;</span><span style="word-wrap: break-word; line-height: 1.5; color: #ff0000;">errno</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">.</span>h<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&gt;</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">#</span><span style="word-wrap: break-word; line-height: 1.5; color: #ff0000;">include</span>&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&lt;</span><span style="word-wrap: break-word; line-height: 1.5; color: #ff0000;">string</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">.</span>h<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&gt;</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">#</span><span style="word-wrap: break-word; line-height: 1.5; color: #ff0000;">include</span>&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&lt;</span>stdlib<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">.</span>h<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&gt;</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><span style="word-wrap: break-word; line-height: 1.5; color: #ff9900;">//扫描所有的lib打头的文件<br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /></span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" />&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000ff;">int</span>&nbsp;filter_fn<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">(</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000ff;">const</span>&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000ff;">struct</span>&nbsp;dirent&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">*</span>&nbsp;ent<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">)</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" />&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">{</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" />&nbsp;&nbsp;&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000ff;">if</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">(</span>ent<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">-</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&gt;</span>d_type&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">!</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">=</span>&nbsp;DT_REG<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">)</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000ff;">return</span>&nbsp;0<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">;</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" />&nbsp;&nbsp;&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000ff;">return</span>&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">(</span><span style="word-wrap: break-word; line-height: 1.5; color: #ff0000;">strncmp</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">(</span>ent<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">-</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&gt;</span>d_name<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">,</span><span style="word-wrap: break-word; line-height: 1.5; color: #ff00ff;">"lib"</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">,</span>3<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">)</span>&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">=</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">=</span>&nbsp;0<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">)</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">;</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" />&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">}</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><span style="word-wrap: break-word; line-height: 1.5; color: #0000ff;">void</span>&nbsp;scan_lib<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">(</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000ff;">char</span>&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">*</span>&nbsp;dir_name<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">)</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">{</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" />&nbsp;&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000ff;">int</span>&nbsp;n<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">;</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" />&nbsp;&nbsp;&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000ff;">struct</span>&nbsp;dirent&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">*</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">*</span>namelist<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">;</span>&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #ff9900;">// struct dirent * namelist[];</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" />&nbsp;&nbsp;&nbsp;n&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">=</span>&nbsp;scandir<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">(</span>dir_name<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">,</span>&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&amp;</span>namelist<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">,</span>&nbsp;filter_fn<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">,</span>&nbsp;alphasort<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">)</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">;</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" />&nbsp;&nbsp;&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000ff;">if</span>&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">(</span>n&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&lt;</span>&nbsp;0<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">)</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #ff0000;">perror</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">(</span><span style="word-wrap: break-word; line-height: 1.5; color: #ff00ff;">"scandir"</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">)</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">;</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" />&nbsp;&nbsp;&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000ff;">else</span>&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">{</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000ff;">while</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">(</span>n<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">-</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">-</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">)</span>&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">{</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #ff0000;">printf</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">(</span><span style="word-wrap: break-word; line-height: 1.5; color: #ff00ff;">"%s\n"</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">,</span>&nbsp;namelist<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">[</span>n<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">]</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">-</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">&gt;</span>d_name<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">)</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">;</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #ff0000;">free</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">(</span>namelist<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">[</span>n<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">]</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">)</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">;</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">}</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #ff0000;">free</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">(</span>namelist<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">)</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">;</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">}</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">}</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><span style="word-wrap: break-word; line-height: 1.5; color: #0000ff;">int</span>&nbsp;main<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">(</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000ff;">int</span>&nbsp;argc&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">,</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000ff;">char</span>&nbsp;<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">*</span>&nbsp;argv<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">[</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">]</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">)</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">{</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" />&nbsp;&nbsp;&nbsp;scan_lib<span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">(</span><span style="word-wrap: break-word; line-height: 1.5; color: #ff00ff;">"/usr/lib"</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">)</span><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">;</span>&nbsp;<br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;">}</span><br style="word-wrap: break-word; line-height: normal; font-family: song, Verdana;" /></span></code></p><div><code style="word-wrap: break-word;"><span style="word-wrap: break-word; line-height: 1.5;"><span style="word-wrap: break-word; line-height: 1.5; color: #0000cc;"><br /></span></span></code></div></td></tr></tbody></table><img src ="http://www.cppblog.com/mysileng/aggbug/196904.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2013-01-02 11:48 <a href="http://www.cppblog.com/mysileng/archive/2013/01/02/196904.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>linux静态链接库与动态链接库的区别及动态库的创建（转）</title><link>http://www.cppblog.com/mysileng/archive/2012/12/30/196854.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Sun, 30 Dec 2012 07:16:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/30/196854.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196854.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/30/196854.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196854.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196854.html</trackback:ping><description><![CDATA[<div style="margin: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #fefef2;">一、引言<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />通常情况下，对函数库的链接是放在编译时期（compile time）完成的。所有相关的对象<span style="margin: 0px; padding: 0px; line-height: 1.5;">文件</span>（object file）与牵涉到的函数库（library）被链接合成一个可执行<span style="margin: 0px; padding: 0px; line-height: 1.5;">文件</span>（executable file）。<span style="margin: 0px; padding: 0px; line-height: 1.5;">程序</span>在<span style="margin: 0px; padding: 0px; line-height: 1.5;">运行</span>时，与函数库再无瓜葛，因为所有需要的函数已拷贝到自己门下。所以这些函数库被成为静态库（static libaray），通常<span style="margin: 0px; padding: 0px; line-height: 1.5;">文件</span>名为&#8220;libxxx.a&#8221;的形式。<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />其实，我们也可以把对一些库函数的链接载入推迟到程序运行的时期（runtime）。这就是如雷贯耳的动态链接库（dynamic link library）技术。<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />二、动态链接库的特点与优势<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />首先让我们来看一下，把库函数推迟到程序运行时期载入的好处：<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />1. 可以实现进程之间的资源共享。<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />什么概念呢？就是说，某个程序的在运行中要调用某个动态链接库函数的时候，操作<span style="margin: 0px; padding: 0px; line-height: 1.5;">系统</span>首先会查看所有正在运行的程序，看在<span style="margin: 0px; padding: 0px; line-height: 1.5;">内存</span>里是否已有此库函数的拷贝了。如果有，则让其共享那一个拷贝；只有没有才链接载入。这样的模式虽然会带来一些&#8220;动态链接&#8221;额外的开销，却大大的节省了<span style="margin: 0px; padding: 0px; line-height: 1.5;">系统</span>的<span style="margin: 0px; padding: 0px; line-height: 1.5;">内存</span>资源。C的标准库就是动态链接库，也就是说<span style="margin: 0px; padding: 0px; line-height: 1.5;">系统</span>中所有运行的程序共享着同一个C标准库的代码段。<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />2. 将一些程序升级变得简单。用户只需要升级动态链接库，而无需重新编译链接其他原有的代码就可以完成整个程序的升级。Windows 就是一个很好的例子。<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />3. 甚至可以真正坐到链接载入完全由程序员在程序代码中控制。<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />程序员在编写程序的时候，可以明确的指明什么时候或者什么情况下，链接载入哪个动态链接库函数。你可以有一个相当大的<span style="margin: 0px; padding: 0px; line-height: 1.5;">软件</span>，但每次运行的时候，由于不同的操作需求，只有一小部分程序被载入内存。所有的函数本着&#8220;有需求才调入&#8221;的原则，于是大大节省了系统资源。比如现在的<span style="margin: 0px; padding: 0px; line-height: 1.5;">软件</span>通常都能打开若干种不同类型的文件，这些读写操作通常都用动态链接库来实现。在一次运行当中，一般只有一种类型的文件将会被打开。所以直到程序知道文件的类型以后再载入相应的读写函数，而不是一开始就将所有的读写函数都载入，然后才发觉在整个程序中根本没有用到它们。<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />三、动态链接库的创建<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />由于动态链接库函数的共享特性，它们不会被拷贝到可执行文件中。在编译的时候，编译器只会做一些函数名之类的检查。在程序运行的时候，被调用的动态链接库 函数被安置在内存的某个地方，所有调用它的程序将指向这个代码段。因此，这些代码必须实用相对地址，而不是绝对地址。在编译的时候，我们需要告诉编译器， 这些对象文件是用来做动态链接库的，所以要用地址不无关代码（Position Independent Code （PIC））。<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />对gcc编译器，只需添加上 -fPIC 标签，如：<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />gcc -fPIC -c file1.c<br style="margin: 0px; padding: 0px;" />gcc -fPIC -c file2.c<br style="margin: 0px; padding: 0px;" />gcc -shared libxxx.so file1.o file2.o<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />注意到最后一行，-shared 标签告诉编译器这是要建立动态链接库。这与静态链接库的建立很不一样，后者用的是 ar&nbsp;<span style="margin: 0px; padding: 0px; line-height: 1.5;">命令</span>。也注意到，动态链接库的名字形式为 &#8220;libxxx.so&#8221; 后缀名为 &#8220;.so&#8221;<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />四、动态链接库的使用<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />使用动态链接库，首先需要在编译期间让编译器检查一些语法与定义。<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />这与静态库的实用基本一样，用的是 -Lpath 和 -lxxx 标签。如：<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />gcc file1.o file2.o -Lpath -lxxx -o program.exe<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />编译器会先在path文件夹下搜索libxxx.so文件，如果没有找到，继续搜索libxxx.a（静态库）。<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />在程序运行期间，也需要告诉系统去哪里找你的动态链接库文件。在UNIX下是通过定义名为 LD_LIBRARY_PATH 的环境变量来实现的。只需将path赋值给此变量即可。csh 命令为：<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />setenv LD_LIBRARY_PATH your/full/path/to/dll<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />一切安排妥当后，你可以用 ldd 命令检查是否连接正常。<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />ldd program.exe</div><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 19px; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #fefef2;"><br style="margin: 0px; padding: 0px;" />动态链接库*.so的编译与使用- -<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />动态库*.so在linux下用c和c++编程时经常会碰到，最近在网站找了几篇文章介绍动态库的编译和链接，总算搞懂了这个之前一直不太了解得东东，这里做个笔记，也为其它正为动态库链接库而苦恼的兄弟们提供一点帮助。<br style="margin: 0px; padding: 0px;" />1、动态库的编译<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />下面通过一个例子来介绍如何生成一个动态库。这里有一个头文件：so_test.h，三个.c文件：test_a.c、test_b.c、test_c.c，我们将这几个文件编译成一个动态库：libtest.so。<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />so_test.h：<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />#include&nbsp;<br style="margin: 0px; padding: 0px;" />#include&nbsp;<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />void test_a();<br style="margin: 0px; padding: 0px;" />void test_b();<br style="margin: 0px; padding: 0px;" />void test_c();<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />test_a.c：<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />#include "so_test.h"<br style="margin: 0px; padding: 0px;" />void test_a()<br style="margin: 0px; padding: 0px;" />{<br style="margin: 0px; padding: 0px;" />printf("this is in test_a...\n");<br style="margin: 0px; padding: 0px;" />}</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 19px; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #fefef2;"><br style="margin: 0px; padding: 0px;" />test_b.c：<br style="margin: 0px; padding: 0px;" />#include "so_test.h"<br style="margin: 0px; padding: 0px;" />void test_b()<br style="margin: 0px; padding: 0px;" />{<br style="margin: 0px; padding: 0px;" />printf("this is in test_b...\n");<br style="margin: 0px; padding: 0px;" />}<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />test_a.c：<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />#include "so_test.h"<br style="margin: 0px; padding: 0px;" />void test_c()<br style="margin: 0px; padding: 0px;" />{<br style="margin: 0px; padding: 0px;" />printf("this is in test_c...\n");<br style="margin: 0px; padding: 0px;" />}<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />将这几个文件编译成一个动态库：libtest.so<br style="margin: 0px; padding: 0px;" />$ gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />2、动态库的链接<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />在1、中，我们已经成功生成了一个自己的动态链接库libtest.so，下面我们通过一个程序来调用这个库里的函数。程序的源文件为：test.c。<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />test.c：</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; line-height: 19px; font-size: 13px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #fefef2;">#include "so_test.h"<br style="margin: 0px; padding: 0px;" />int main()<br style="margin: 0px; padding: 0px;" />{<br style="margin: 0px; padding: 0px;" />test_a();<br style="margin: 0px; padding: 0px;" />test_b();<br style="margin: 0px; padding: 0px;" />test_c();<br style="margin: 0px; padding: 0px;" />return 0;<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />}<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />l 将test.c与动态库libtest.so链接生成执行文件test：<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />$ gcc test.c -L. -ltest -o test<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />l 测试是否动态连接，如果列出libtest.so，那么应该是连接正常了<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />$ ldd test<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />l 执行test，可以看到它是如何调用动态库中的函数的。<br style="margin: 0px; padding: 0px;" />3、编译参数解析<br style="margin: 0px; padding: 0px;" />最主要的是GCC命令行的一个选项:<br style="margin: 0px; padding: 0px;" />-shared 该选项指定生成动态连接库（让连接器生成T类型的导出符号表，有时候也生成弱连接W类型的导出符号），不用该标志外部程序无法连接。相当于一个可执行文件<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />l -fPIC：表示编译为位置独立的代码，不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要，而不能达到真正代码段共享的目的。<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />l -L.：表示要连接的库在当前目录中<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />l -ltest：编译器查找动态连接库时有隐含的命名规则，即在给出的名字前面加上lib，后面加上.so来确定库的名称<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />l LD_LIBRARY_PATH：这个环境变量指示动态连接器可以装载动态库的路径。<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />l 当然如果有root权限的话，可以修改/etc/ld.so.conf文件，然后调用 /sbin/ldconfig来达到同样的目的，不过如果没有root权限，那么只能采用输出LD_LIBRARY_PATH的方法了。<br style="margin: 0px; padding: 0px;" />4、注意<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" />调用动态库的时候有几个问题会经常碰到，有时，明明已经将库的头文件所在目录 通过 &#8220;-I&#8221; include进来了，库所在文件通过 &#8220;-L&#8221;参数引导，并指定了&#8220;-l&#8221;的库名，但通过ldd命令察看时，就是死活找不到你指定链接的so文件，这时你要作的就是通过修改 LD_LIBRARY_PATH或者/etc/ld.so.conf文件来指定动态库的目录。通常这样做就可以解决库无法链接的问题了。</p><img src ="http://www.cppblog.com/mysileng/aggbug/196854.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-30 15:16 <a href="http://www.cppblog.com/mysileng/archive/2012/12/30/196854.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于centos 5.5 程序中编译出现curses.h不存在问题(转)</title><link>http://www.cppblog.com/mysileng/archive/2012/12/29/196775.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Sat, 29 Dec 2012 02:56:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/29/196775.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196775.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/29/196775.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196775.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196775.html</trackback:ping><description><![CDATA[<span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">&nbsp; 检查是否已经安装以下的辅助软件包</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; " /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">&nbsp; &nbsp; &nbsp; &nbsp; 　　[root@localhost ~]#&nbsp;</span><span style="font-family: Arial; line-height: 26px; background-color: #ffffff; color: #ff0000; ">rpm -q ncurses<br /></span><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">&nbsp; &nbsp; &nbsp; &nbsp; 　　ncurses-5.5-24.</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; " /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">&nbsp; &nbsp; &nbsp; &nbsp; 　　[root@localhost ~]#&nbsp;</span><span style="font-family: Arial; line-height: 26px; background-color: #ffffff; color: #ff0000; ">&nbsp;rpm -q ncurses-devel<br /></span><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">&nbsp; &nbsp; &nbsp; &nbsp; 　　package ncurses-devel is not installed</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; " /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;提示ncurses-devel没有安装，用yum安装：</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; " /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">&nbsp; &nbsp; &nbsp; &nbsp; 　　[root@localhost ~]#&nbsp;&nbsp;</span><span style="font-family: Arial; line-height: 26px; background-color: #ffffff; color: #ff0000; ">yum install ncurses-devel<br /></span><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">&nbsp; &nbsp; &nbsp; &nbsp; 　　Setting up Install Process</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; " /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">&nbsp; &nbsp; &nbsp; &nbsp; 　　Total download size: 1.6 M</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; " /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">&nbsp; &nbsp; &nbsp; &nbsp; 　　Is this ok [y/N]:</span><span style="font-family: Arial; line-height: 26px; background-color: #ffffff; color: #ff0000; ">&nbsp;y<br /></span><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">&nbsp; &nbsp; &nbsp; &nbsp; 　　Downloading Packages:</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; " /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">&nbsp; &nbsp; &nbsp; &nbsp; 　　Installed:&nbsp;&nbsp;ncurses-devel.i386 0:5.5-24.</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; " /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">&nbsp; &nbsp; &nbsp; &nbsp; 　　Complete!</span>&nbsp;<br /><br /><pre id="best-content-1074225391" accuse="aContent"  mb-10"="" style="margin-top: 0px; margin-bottom: 10px; padding: 0px; font-family: arial, 'courier new', courier, 宋体, monospace; white-space: pre-wrap; word-wrap: break-word; line-height: 24px; background-color: #fffcf6; ">链接要加上ncurses库, cc -l ncurses xxxx.c</pre><br />转自:<a href="http://blog.csdn.net/xumaojun/article/details/6229789">http://blog.csdn.net/xumaojun/article/details/6229789</a><img src ="http://www.cppblog.com/mysileng/aggbug/196775.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-29 10:56 <a href="http://www.cppblog.com/mysileng/archive/2012/12/29/196775.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>brk(), sbrk() 用法详解 (转)</title><link>http://www.cppblog.com/mysileng/archive/2012/12/27/196705.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Thu, 27 Dec 2012 04:15:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/27/196705.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196705.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/27/196705.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196705.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196705.html</trackback:ping><description><![CDATA[<span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">brk() , sbrk() 的声明如下：<br /></span><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#include&nbsp;&lt;unistd.h&gt;<br /><span style="color: #0000FF; ">int</span>&nbsp;brk(<span style="color: #0000FF; ">void</span>&nbsp;*addr);<br /><span style="color: #0000FF; ">void</span>&nbsp;*sbrk(intptr_t&nbsp;increment);</div><span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">这两个函数都用来改变 "program break" (程序间断点)的位置，这个位置可参考下图：</span><p style="margin: 0px; padding: 0px; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"></p><p style="margin: 0px; padding: 0px; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><img src="http://my.csdn.net/uploads/201207/22/1342931565_1627.png" alt="" style="border: none;" /></p><p style="margin: 0px; padding: 0px; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">如 man 里说的：<br /></p><blockquote class="blockquote3" style="color: #000000; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><div class="quote" style="color: #999999; font-size: 12px;">引用</div><div class="text" style="padding: 15px; font-size: 12px;">brk()&nbsp;&nbsp;and&nbsp;&nbsp;sbrk() change the location of the program break, which defines the end of the process's data segment (i.e., the program break is the first location after the end of the uninitialized data segment).&nbsp;&nbsp;</div></blockquote><span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">brk() 和 sbrk() 改变 "program brek" 的位置，这个位置定义了进程数据段的终止处(也就是说，program break 是在未初始化数据段终止处后的第一个位置)。</span><br style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;" /><span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">如此翻译过来，似乎会让人认为这个 program break 是和上图中矛盾的，上图中的 program break 是在堆的增长方向的第一个位置处(堆和栈的增长方向是相对的)，而按照说明手册来理解，似乎是在 bss segment 结束那里(因为未初始化数据段一般认为是 bss segment)。</span><span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"></span><p style="margin: 0px; padding: 0px; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"></p><p style="margin: 0px; padding: 0px; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><br />首先说明一点，一个程序一旦编译好后，text segment ，data segment 和 bss segment 是确定下来的，这也可以通过 objdump 观察到。下面通过一个程序来测试这个 program break 是不是在 bss segment 结束那里：</p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#include&nbsp;&lt;stdio.h&gt;<br />#include&nbsp;&lt;unistd.h&gt;<br />#include&nbsp;&lt;stdlib.h&gt;<br />#include&nbsp;&lt;sys/time.h&gt;<br />#include&nbsp;&lt;sys/resource.h&gt;<br />&nbsp;<br />&nbsp;<br /><span style="color: #0000FF; ">int</span>&nbsp;bssvar;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">声明一个味定义的变量，它会放在&nbsp;bss&nbsp;segment&nbsp;中</span><span style="color: #008000; "><br /></span>&nbsp;<br />&nbsp;<br /><span style="color: #0000FF; ">int</span>&nbsp;main(<span style="color: #0000FF; ">void</span>)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;*pmem;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">long</span>&nbsp;heap_gap_bss;<br />&nbsp;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;printf&nbsp;("end&nbsp;of&nbsp;bss&nbsp;section:%p\n",&nbsp;(<span style="color: #0000FF; ">long</span>)&amp;bssvar&nbsp;+&nbsp;4);<br />&nbsp;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;pmem&nbsp;=&nbsp;(<span style="color: #0000FF; ">char</span>&nbsp;*)malloc(32);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">从堆中分配一块内存区，一般从堆的开始处获取</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(pmem&nbsp;==&nbsp;NULL)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;perror("malloc");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit&nbsp;(EXIT_FAILURE);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;printf&nbsp;("pmem:%p\n",&nbsp;pmem);<br />&nbsp;<br />&nbsp;<br /><span style="color: #008000; ">//</span><span style="color: #008000; ">计算堆的开始地址和&nbsp;bss&nbsp;segment&nbsp;结束处得空隙大小，注意每次加载程序时这个空隙都是变化的，但是在同一次加载中它不会改变</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;heap_gap_bss&nbsp;=&nbsp;(<span style="color: #0000FF; ">long</span>)pmem&nbsp;-&nbsp;(<span style="color: #0000FF; ">long</span>)&amp;bssvar&nbsp;-&nbsp;4;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;printf&nbsp;("1-gap&nbsp;between&nbsp;heap&nbsp;and&nbsp;bss:%lu\n",&nbsp;heap_gap_bss);<br />&nbsp;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;free&nbsp;(pmem);&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">释放内存，归还给堆</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;sbrk(32);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">调整&nbsp;program&nbsp;break&nbsp;位置(假设现在不知道这个位置在堆头还是堆尾)</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pmem&nbsp;=&nbsp;(<span style="color: #0000FF; ">char</span>&nbsp;*)malloc(32);&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">再一次获取内存区</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(pmem&nbsp;==&nbsp;NULL)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;perror("malloc");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit&nbsp;(EXIT_FAILURE);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf&nbsp;("pmem:%p\n",&nbsp;pmem);&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">检查和第一次获取的内存区的起始地址是否一样</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;heap_gap_bss&nbsp;=&nbsp;(<span style="color: #0000FF; ">long</span>)pmem&nbsp;-&nbsp;(<span style="color: #0000FF; ">long</span>)&amp;bssvar&nbsp;-&nbsp;4;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">计算调整&nbsp;program&nbsp;break&nbsp;后的空隙</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;printf&nbsp;("2-gap&nbsp;between&nbsp;heap&nbsp;and&nbsp;bss:%lu\n",&nbsp;heap_gap_bss);<br />&nbsp;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;free(pmem);&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">释放</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />}</div><span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">下面，我们分别运行两次程序，并查看其输出：</span><br style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;" /><br style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;" /><br style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;" /><p style="margin: 0px; padding: 0px; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"></p><blockquote class="blockquote3" style="color: #000000; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><div class="quote" style="color: #999999; font-size: 12px;">引用</div><div class="text" style="padding: 15px; font-size: 12px;">[beyes@localhost C]$ ./sbrk&nbsp;<br />end of bss section:0x8049938<br />pmem:0x82ec008<br />1-gap between heap and bss:2762448<br />pmem:0x82ec008<br />2-gap between heap and bss:2762448<br />[beyes@localhost C]$ ./sbrk&nbsp;<br />end of bss section:0x8049938<br />pmem:0x8dbc008<br />1-gap between heap and bss:14100176<br />pmem:0x8dbc008<br />2-gap between heap and bss:14100176</div></blockquote><span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">从上面的输出中，可以发现几点：</span><br style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;" /><span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">1. bss 段一旦在在程序编译好后，它的地址就已经规定下来。</span><br style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;" /><span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">2. 一般及简单的情况下，使用 malloc() 申请的内存，释放后，仍然归还回原处，再次申请同样大小的内存区时，还是从第 1 次那里获得。</span><br style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;" /><span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">3. bss segment 结束处和堆的开始处的空隙大小，并不因为 sbrk() 的调整而改变，也就是说明了 program break 不是调整堆头部。</span><br style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;" /><br style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;" /><span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff; color: red;">所以，man 手册里所说的&nbsp;&nbsp;&#8220;program break 是在未初始化数据段终止处后的第一个位置&#8221; ，不能将这个位置理解为堆头部。这时，可以猜想应该是在堆尾部，也就是堆增长方向的最前方</span><span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">。下面用程序进行检验：</span><br style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;" /><br style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;" /><span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">当 sbrk() 中的参数为 0 时，我们可以找到 program break 的位置。那么根据这一点，检查一下每次在程序加载时，系统给堆的分配是不是等同大小的：</span><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#include&nbsp;&lt;stdio.h&gt;<br />#include&nbsp;&lt;unistd.h&gt;<br />#include&nbsp;&lt;stdlib.h&gt;<br />#include&nbsp;&lt;sys/time.h&gt;<br />#include&nbsp;&lt;sys/resource.h&gt;<br />&nbsp;<br />&nbsp;<br /><span style="color: #0000FF; ">int</span>&nbsp;main(<span style="color: #0000FF; ">void</span>)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;*tret;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;*pmem;<br />&nbsp;<br />&nbsp;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pmem&nbsp;=&nbsp;(<span style="color: #0000FF; ">char</span>&nbsp;*)malloc(32);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(pmem&nbsp;==&nbsp;NULL)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;perror("malloc");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit&nbsp;(EXIT_FAILURE);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf&nbsp;("pmem:%p\n",&nbsp;pmem);<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tret&nbsp;=&nbsp;sbrk(0);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(tret&nbsp;!=&nbsp;(<span style="color: #0000FF; ">void</span>&nbsp;*)-1)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf&nbsp;("heap&nbsp;size&nbsp;on&nbsp;each&nbsp;load:&nbsp;%lu\n",&nbsp;(<span style="color: #0000FF; ">long</span>)tret&nbsp;-&nbsp;(<span style="color: #0000FF; ">long</span>)pmem);<br />&nbsp;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />}</div><span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">运行上面的程序 3 次：</span><br style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;" /><p style="margin: 0px; padding: 0px; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"></p><blockquote style="color: #000000; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><div style="color: #999999; font-size: 12px;">引用</div><div style="padding: 15px; font-size: 12px;">[beyes@localhost C]$ ./sbrk&nbsp;<br />pmem:0x80c9008<br />heap size on each load: 135160<br />[beyes@localhost C]$ ./sbrk&nbsp;<br />pmem:0x9682008<br />heap size on each load: 135160<br />[beyes@localhost C]$ ./sbrk&nbsp;<br />pmem:0x9a7d008<br />heap size on each load: 135160<br />[beyes@localhost C]$ ./sbrk&nbsp;<br />pmem:0x8d92008<br />heap size on each load: 135160<br />[beyes@localhost C]$ vi sbrk.c</div></blockquote><span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">从输出可以看到，虽然堆的头部地址在每次程序加载后都不一样，但是每次加载后，堆的大小默认分配是一致的。但是这不是不能改的，可以使用 sysctl 命令修改一下内核参数：</span><br style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;" /><blockquote style="color: #000000; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><div style="color: #999999; font-size: 12px;">引用</div><div style="padding: 15px; font-size: 12px;">#sysctl -w kernel/randomize_va_space=0</div></blockquote><span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">这么做之后，再运行 3 次这个程序看看：</span><br style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;" /><blockquote style="color: #000000; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><div style="color: #999999; font-size: 12px;">引用</div><div style="padding: 15px; font-size: 12px;">[beyes@localhost C]$ ./sbrk&nbsp;<br />pmem:0x804a008<br />heap size on each load: 135160<br />[beyes@localhost C]$ ./sbrk&nbsp;<br />pmem:0x804a008<br />heap size on each load: 135160<br />[beyes@localhost C]$ ./sbrk&nbsp;<br />pmem:0x804a008<br />heap size on each load: 135160</div></blockquote><span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">从输出看到，每次加载后，堆头部的其实地址都一样了。但我们不需要这么做，每次堆都一样，容易带来缓冲区溢出攻击(以前老的 linux 内核就是特定地址加载的)，所以还是需要保持 randomize_va_space 这个内核变量值为 1 。</span><br style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;" /><br style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;" /><span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">下面就来验证 sbrk() 改变的 program break 位置在堆的增长方向处：</span><br /><div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all;"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#include&nbsp;&lt;stdio.h&gt;<br />#include&nbsp;&lt;unistd.h&gt;<br />#include&nbsp;&lt;stdlib.h&gt;<br />#include&nbsp;&lt;sys/time.h&gt;<br />#include&nbsp;&lt;sys/resource.h&gt;<br />&nbsp;<br />&nbsp;<br /><span style="color: #0000FF; ">int</span>&nbsp;main(<span style="color: #0000FF; ">void</span>)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;*tret;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;*pmem;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;i;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">long</span>&nbsp;sbrkret;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pmem&nbsp;=&nbsp;(<span style="color: #0000FF; ">char</span>&nbsp;*)malloc(32);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(pmem&nbsp;==&nbsp;NULL)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;perror("malloc");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit&nbsp;(EXIT_FAILURE);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf&nbsp;("pmem:%p\n",&nbsp;pmem);<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;(i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;65;&nbsp;i++)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sbrk(1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf&nbsp;("%d\n",&nbsp;sbrk(0)&nbsp;-&nbsp;(<span style="color: #0000FF; ">long</span>)pmem&nbsp;-&nbsp;0x20ff8);&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">0x20ff8&nbsp;就是堆预分配的固定大小；改变后要用&nbsp;sbrk(0)&nbsp;再次获取更新后的program&nbsp;break位置</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;free(pmem);<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />}</div><span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">运行输出：</span><br style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;" /><p style="margin: 0px; padding: 0px; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"></p><blockquote style="color: #000000; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><div style="color: #999999; font-size: 12px;">引用</div><div style="padding: 15px; font-size: 12px;">[beyes@localhost C]$ ./sbrk&nbsp;<br />pmem:0x804a008<br />1<br />2<br />3<br />4<br />5<br /><br />... ...<br />61<br />62<br />63<br />64</div></blockquote><br style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;" /><span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">从输出看到，sbrk(1) 每次让堆往栈的方向增加 1 个字节的大小空间。</span><span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><br /></span><p style="margin: 0px; padding: 0px; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"></p><p style="margin: 0px; padding: 0px; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">而 brk() 这个函数的参数是一个地址，假如你已经知道了堆的起始地址，还有堆的大小，<span style="color: red;">那么你就可以据此修改 brk() 中的地址参数已达到调整堆的目的。</span><br /></p><p style="margin: 0px; padding: 0px; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">实际上，在应用程序中，基本不直接使用这两个函数，取而代之的是 malloc() 一类函数，这一类库函数的执行效率会更高。&nbsp;还需要注意一点，当使用 malloc() 分配过大的空间，比如超出 0x20ff8 这个常数(在我的系统(Fedora15)上是这样，别的系统可能会有变)时，malloc 不再从堆中分配空间，而是使用 mmap() 这个系统调用从映射区寻找可用的内存空间。<br /><br /><br />brk/sbrk我觉得：一个程序可寻址的逻辑地址范围是3G（本来是4G，有1G是内核空间不能用），但是这只是逻辑地址，并不可能全部给你用，所以就把预定约定可以给你用的那部分空间(code\data\bss\heap\stack)映射成了物理地址。但是预先约定的总有不够用的时候，此时可以通过brk/sbrk来增加逻辑地址到物理地址映射的范围，即扩大该程序堆空间的大小。<br /></p><img src ="http://www.cppblog.com/mysileng/aggbug/196705.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-27 12:15 <a href="http://www.cppblog.com/mysileng/archive/2012/12/27/196705.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>writev和write性能比较（转）  </title><link>http://www.cppblog.com/mysileng/archive/2012/12/18/196394.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Tue, 18 Dec 2012 03:33:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/18/196394.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196394.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/18/196394.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196394.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196394.html</trackback:ping><description><![CDATA[<p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; ">今天突然想比较一下 write() 和 writev() 的性能， 网上google了半天， 竟然没有发现一点有关的数据信息， 自己就测试了一下。</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; ">平台如下：</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; ">CentOS 5.2 Linux kernel 2.6.18-92.e15</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; ">CPU: Intel(R) Pentium(R) 4 CPU 2.40GHz</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; ">Disk: 7200 rpm</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; ">测试的想法是: 对于writev（）， 如果有10 个buffer， 并且buffer的大小是1kb,&nbsp; 那么我就先依次调用write() 10 次， 每次写1KB 到同一个文件， 记录下时间， 然后记录下用writev（）的时间。 最后， 以write（）为baseline, 计算writev（）所占的%， 如果%越小， 证明writev() 的性能就越好。</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; ">做了两组测试，</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; ">第一组， 固定buffer 的个数（10， 100， 1000）， 依次增加buffer的大小， 从1KB -- 1024KB， 数据如下， （基准线为相应write（）的数据）</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; ">例如， 10 个buffer， 每个buffer size 是1KB。 write() 耗时0.092 ms, writev() 耗时0.098 ms, 图中的数据即为 1.067 (write_v10, 1KB)</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; ">图一<img alt="writev和write性能比较（转） - 光明磊落 - 光明磊落的博客" src="http://www.cppblog.com/images/cppblog_com/whoami17/writ_v10.gif" border="0" style="border: 0px; max-width: 100%; " /></p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; ">&nbsp;</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; ">第二组， 固定buffer大小（1KB， 2KB， 8KB）， 依次增加buffer的数目， 从 200 -- 8000, 数据如下 （基准线为相应write（）的数据）</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; ">图二</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; "><img alt="writev和write性能比较（转） - 光明磊落 - 光明磊落的博客" src="http://www.cppblog.com/images/cppblog_com/whoami17/write_1KB.gif" border="0" style="border: 0px; max-width: 100%; " /></p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; ">第一组数据显示：1. &nbsp;随着buffer的增大 （ &gt; 64KB）， writev（）的性能开始跟write（）持平； 2. 如果buffer的个数过小 ， writev（）的性能是低于write（）的。 从图一可以看到，&nbsp; 在buffer size 小于1024KB 时， writev（） 使用10 个buffer的性能要低于100 和1000。</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; ">第二组数据显示： 1. 当保持buffer size一定情况下， 增加buffer的个数 （&lt; 2000）， writev（） 的性能稳定在70%左右; 2.&nbsp;增加buffer&nbsp;size,&nbsp;将会降低writev()的性能。 当buffer为8KB 时， writev（）&nbsp;所用时间基本上都为相应write（）时间的80%， 性能的提高明显不如1KB 和 2KB。3.&nbsp;当buffer的个数超过2000， 并且buffer size 大于2KB， writev（）性能将远不如write（）。</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; ">结论：</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; ">writev() 应使用在small write intensive 的workload中，&nbsp;buffer&nbsp;size&nbsp;应控制在 2KB 以下， 同时buffer的数目不要超过IOV_MAX,&nbsp;否则 writev()&nbsp;并不会带来性能的提高。&nbsp;</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; ">&nbsp;</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; ">现在， 所要研究的问题是对于不同的workload， 如何快速的确定writev（）中buffer的个数和大小， 从而达到较好performance。</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #555555; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; text-indent: 2em; ">Saturday, May 09, 2009&nbsp; 8:50:48 PM</p><img src ="http://www.cppblog.com/mysileng/aggbug/196394.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-18 11:33 <a href="http://www.cppblog.com/mysileng/archive/2012/12/18/196394.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>建议性锁和强制性锁机制下的锁（原）</title><link>http://www.cppblog.com/mysileng/archive/2012/12/17/196372.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Mon, 17 Dec 2012 04:24:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/17/196372.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196372.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/17/196372.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196372.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196372.html</trackback:ping><description><![CDATA[&nbsp; &nbsp; &nbsp;首先，建议性锁和强制性锁并不是真正存在的锁，而是一种能对诸如记录锁、文件锁效果产生影响的两种机制。<br /><br /><div>1.建议性锁机制是这样规定的：每个使用文件的进程都要<span style="color: red; ">主动检查</span>该文件是否有锁存在，当然都是通过具体锁的API，比如fctl记录锁F_GETTLK来主动检查是否有锁存在。如果有锁存在并被排斥，那么就<span style="color: red; ">主动</span><span style="color: red; ">保证</span>不再进行接下来的IO操作。如果每一个进程都主动进行检查，并主动保证，那么就说这些进程都以一致性的方法处理锁，（这里的一致性方法就是之前说的两个主动）。但是这种一致性方法依赖于编写进程程序员的素质，也许有的程序员编写的进程程序遵守这个一致性方法，有的不遵守。不遵守的程序员编写的进程程序会怎么做呢？也许会不主动判断这个文件有没有加上文件锁或记录锁，就直接对这个文件进行IO操作。此时这种有破坏性的IO操作会不会成功呢？如果是在建议性锁的机制下，这种破坏性的IO就会成功。因为锁只是建议性存在的，并不强制执行。内核和系统总体上都坚持不使用建议性锁机制，它们依靠程序员遵守这个规定。（Linux默认是采用建议性锁）<br /><br />2.强制性锁机制是这样规定的：&nbsp;所有记录或文件锁功能内核执行的。上述提到的破坏性IO操作会被内核禁止。当文件被上锁来进行读写操作时，在锁定该文件的进程释放该锁之前，内核会强制阻止任何对该文件的读或写违规访问，每次读或写访问都得检查锁是否存在。也就是强制性锁机制，让锁变得名副其实，真正达到了锁的效果，而不是像建议性锁机制那样只是个纸老虎。= =！<br /><span style="font-family: Simsun; line-height: 16.78333282470703px; background-color: #f7f7f7; ">&nbsp; &nbsp;设置强制性文件锁的</span><span style="font-family: Simsun; line-height: 16.78333282470703px; background-color: #f7f7f7; ">方式比较特别:</span><br style="font-family: Simsun; line-height: 16.78333282470703px; " /><br style="font-family: Simsun; line-height: 16.78333282470703px; " /><span style="font-family: Simsun; line-height: 16.78333282470703px; background-color: #f7f7f7; ">&nbsp;&nbsp;&nbsp;chmod&nbsp;g+s&nbsp;&lt;filename&gt;</span><br style="font-family: Simsun; line-height: 16.78333282470703px; " /><span style="font-family: Simsun; line-height: 16.78333282470703px; background-color: #f7f7f7; ">&nbsp;&nbsp;&nbsp;chmod&nbsp;g-x&nbsp;&lt;filename&gt;</span><br style="font-family: Simsun; line-height: 16.78333282470703px; " /><br style="font-family: Simsun; line-height: 16.78333282470703px; " /><span style="font-family: Simsun; line-height: 16.78333282470703px; background-color: #f7f7f7; ">&nbsp;&nbsp;&nbsp;这是形象的表示，实际编程中应该通过chmod()函数一步完成。不能对目录、可执</span><span style="font-family: Simsun; line-height: 16.78333282470703px; background-color: #f7f7f7; ">行文件设置强制性锁。</span>&nbsp;<br /><br />3.贴出网上搜到的解释<br /><br /><div>例1，我有几个进程(不一定有亲缘关系)都先通过fctnl锁机制来判断再操作文件，这个就叫一致的方法。参见[2]&nbsp;</div><div>但是，如果同时，又有个流氓进程，管它3721，冲上去，直接open, write一堆操作。&nbsp;</div><div>这时候那几个先fcntl 再操作的进程对这种方式无能为力，这样就叫不一致。文件最后的状态就不定了。&nbsp;</div><div>正因为这种锁约束不了其它的访问方式，所以叫建议行锁。强制性锁需要内核支持的,对read, write, open都会检查锁。<br /></div><div>例2，所谓建议性锁就是假定人们都会遵守某些规则去干一件事。例如，人与车看到红灯都会停，而看到绿灯才会继续走，我们可以称红绿等为建议锁。但这只是一种规则而已，你并不防止某些人强闯红灯。而强制性锁是你想闯红灯也闯不了。</div></div><img src ="http://www.cppblog.com/mysileng/aggbug/196372.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-17 12:24 <a href="http://www.cppblog.com/mysileng/archive/2012/12/17/196372.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>五种I/O 模式——阻塞(默认IO模式)，非阻塞(常用语管道)，I/O多路复用(IO多路复用的应用场景)，信号I/O，异步I/O  (转)</title><link>http://www.cppblog.com/mysileng/archive/2012/12/16/196347.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Sun, 16 Dec 2012 04:21:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/16/196347.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196347.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/16/196347.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196347.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196347.html</trackback:ping><description><![CDATA[<p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #696969; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; "><strong>五种I/O 模式：</strong><br />【1】&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;阻塞 I/O&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (Linux下的I/O操作默认是阻塞I/O，即open和socket创建的I/O都是阻塞I/O)<br />【2】&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;非阻塞 I/O&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (可以通过fcntl或者open时使用O_NONBLOCK参数，将fd设置为非阻塞的I/O)<br />【3】&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;I/O 多路复用&nbsp;&nbsp;&nbsp;&nbsp; (I/O多路复用，通常需要非阻塞I/O配合使用)<br />【4】&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;信号驱动 I/O&nbsp;&nbsp;&nbsp; (SIGIO)<br />【5】&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;异步 I/O</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #696969; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; ">&nbsp;</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #696969; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; ">一般来说，程序进行输入操作有两步：<br />1．等待有数据可以读<br />2．将数据从系统内核中拷贝到程序的数据区。</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #696969; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; ">对于sock编程来说:</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #696969; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第一步:&nbsp;&nbsp; 一般来说是等待数据从网络上传到本地。当数据包到达的时候，数据将会从网络层拷贝到内核的缓存中；</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #696969; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第二步:&nbsp;&nbsp; 是从内核中把数据拷贝到程序的数据区中。</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #696969; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; ">&nbsp;</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #696969; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; "><strong><span style="line-height: 28px; font-size: 16px; ">阻塞I/O模式&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; //进程处于阻塞模式时，让出CPU，进入休眠状态</span><br /></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;阻塞 I/O 模式是最普遍使用的 I/O 模式。是Linux系统下<span style="color: #5500ff; ">缺省的IO模式。</span></p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #696969; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;大部分程序使用的都是阻塞模式的 I/O 。</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #696969; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个套接字建立后所处于的模式就是<span style="color: #5500ff; ">阻塞 I/O 模式</span>。（因为Linux系统默认的IO模式是阻塞模式）</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #696969; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; "><br />对于一个&nbsp;<span style="color: #5500ff; ">UDP 套接字</span>来说，数据就绪的标志比较简单：<br />（1）已经收到了一整个数据报<br />（2）没有收到。<br />而 TCP 这个概念就比较复杂，需要附加一些其他的变量。</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #696969; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一个进程调用 recvfrom&nbsp; ，然后系统调用并不返回知道有数据报到达本地系统，然后系统将数据拷贝到进程的缓存中。 （如果系统调用收到一个中断信号，则它的调用会被中断）</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #696969; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ffffff; "><span style="color: #5500ff; ">&nbsp;&nbsp;&nbsp;我们称这个进程在调用recvfrom一直到从recvfrom返回这段时间是阻塞的。</span>当recvfrom正常返回时，我们的进程继续它的操作。</p><div><img src="http://www.cppblog.com/images/cppblog_com/mysileng/954763121003157249.png" width="750" height="435" alt="" /></div><div>&nbsp;</div><div>&nbsp;---------------------------------------------------------------------------------</div><div><p style="margin: 0px 0px 10px; padding: 0px; "><strong><span style="line-height: 28px; font-size: 16px; ">非阻塞模式I/O&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; //非阻塞模式的使用并不普遍，因为非阻塞模式会浪费大量的CPU资源。</span></strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当我们将一个套接字设置为非阻塞模式，我们相当于告诉了系统内核： &#8220;当我请求的I/O 操作不能够马上完成，你想让我的进程进行休眠等待的时候，不要这么做，请马上返回一个错误给我。&#8221;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们开始对 recvfrom 的三次调用，因为系统还没有接收到网络数据，所以内核马上返回一个&nbsp;<span style="background-color: #5500ff; ">EWOULDBLOCK</span>的错误。</p><p style="margin: 0px 0px 10px; padding: 0px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第四次我们调用 recvfrom 函数，一个数据报已经到达了，内核将它拷贝到我们的应用程序的缓冲区中，然后 recvfrom 正常返回，我们就可以对接收到的数据进行处理了。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当一个应用程序使用了非阻塞模式的套接字，它需要使用一个循环来不听的测试是否一个文件描述符有数据可读(称做 polling(轮询))。应用程序不停的 polling 内核来检查是否 I/O操作已经就绪。<span style="color: #5500ff; ">这将是一个极浪费 CPU资源的操作</span>。这种模式使用中不是很普遍。</p><div>&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/mysileng/2263340287731850468.png" width="750" height="377" alt="" /><div>例如:</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对管道的操作，最好使用非阻塞方式！</div><div>&nbsp;</div><div>&nbsp;</div><div>&nbsp;&nbsp;---------------------------------------------------------------------------------</div><div>&nbsp;</div><p style="margin: 0px 0px 10px; padding: 0px; "><strong><span style="line-height: 28px; font-size: 16px; ">I/O多路复用&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; //针对批量IP操作时，使用I/O多路复用，非常有好。</span></strong></p><div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在使用 I/O 多路技术的时候，我们调用&nbsp;<span style="color: #5500ff; ">select()函数和 poll()函数或epoll函数(2.6内核开始支持)</span>，在调用它们的时候阻塞，而不是我们来调用 recvfrom（或recv）的时候阻塞。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当我们调用 select函数阻塞的时候，select 函数等待数据报套接字进入读就绪状态。当select函数返回的时候， 也就是套接字可以读取数据的时候。 这时候我们就可以调用 recvfrom函数来将数据拷贝到我们的程序缓冲区中。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对于单个I/O操作，和阻塞模式相比较，select()和poll()或epoll并没有什么高级的地方。</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 而且，在阻塞模式下只需要调用一个函数：</div><div>&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; 读取或发送函数。</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在使用了多路复用技术后，我们需要调用两个函数了：</div><div>&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;&nbsp;先调用 select()函数或poll()函数，然后才能进行真正的读写。</div><p style="margin: 0px 0px 10px; padding: 0px; "><span style="color: #5500ff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;多路复用的高级之处在于::</span></p><p style="margin: 0px 0px 10px; padding: 0px; "><span style="color: #5500ff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;它能同时等待多个文件描述符，而这些文件描述符（套接字描述符）其中的任意一个进入读就绪状态，select()函数就可以返回。</span></p><div>&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/mysileng/3102135718329445318.png" width="750" height="377" alt="" /><div><span style="color: #5500ff;">IO 多路技术一般在下面这些情况中被使用：</span></div><div>1、当一个客户端需要同时处理多个文件描述符的输入输出操作的时候（一般来说是标准的输入输出和网络套接字)，I/O 多路复用技术将会有机会得到使用。<br />2、当程序需要同时进行多个套接字的操作的时候。<br />3、如果一个 TCP 服务器程序同时处理正在侦听网络连接的套接字和已经连接好的套接字。<br />4、如果一个服务器程序同时使用 TCP 和 UDP 协议。<br />5、如果一个服务器同时使用多种服务并且每种服务可能使用不同的协议（比如 inetd就是这样的）。</div><div>&nbsp;</div><div>&nbsp;</div><div>&nbsp;</div><div>异步IO模式有::</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、信号驱动I/O模式</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2、异步I/O模式</div><div><strong><span style="line-height: 28px; font-size: 16px; ">信号驱动I/O模式&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //自己没有用过。</span><br /></strong></div><p style="margin: 0px 0px 10px; padding: 0px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;我们可以使用信号，让内核在文件描述符就绪的时候使用 SIGIO 信号来通知我们。我们将这种模式称为信号驱动 I/O 模式。</p><p style="margin: 0px 0px 10px; padding: 0px; "><img src="http://www.cppblog.com/images/cppblog_com/mysileng/5791910595775213301.jpg" width="674" height="459" alt="" /><br />为了在一个套接字上使用信号驱动 I/O 操作，下面这三步是所必须的。</p><div>（1）一个和 SIGIO信号的处理函数必须设定。<br />（2）套接字的拥有者必须被设定。一般来说是使用 fcntl 函数的 F_SETOWN 参数来<br />进行设定拥有者。<br />（3）套接字必须被允许使用异步 I/O。一般是通过调用 fcntl 函数的 F_SETFL 命令，O_ASYNC为参数来实现。</div><p style="margin: 0px 0px 10px; padding: 0px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 虽然设定套接字为异步 I/O 非常简单，但是使用起来困难的部分是怎样在程序中断定产生 SIGIO信号发送给套接字属主的时候，程序处在什么状态。</p><div><span style="color: #5500ff; ">1．UDP 套接字的 SIGIO 信号&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (比较简单)</span><br />在 UDP 协议上使用异步 I/O 非常简单．这个信号将会在这个时候产生：</div><div>1、套接字收到了一个数据报的数据包。<br />2、套接字发生了异步错误。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当我们在使用 UDP 套接字异步 I/O 的时候，我们使用 recvfrom()函数来读取数据报数据或是异步 I/O 错误信息。<br /><span style="color: #5500ff; ">2．TCP 套接字的 SIGIO 信号&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (不会使用)</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不幸的是，异步 I/O 几乎对 TCP 套接字而言没有什么作用。因为对于一个 TCP 套接字来说，<span style="color: #5500ff; ">SIGIO 信号发生的几率太高了</span>，所以 SIGIO 信号并不能告诉我们究竟发生了什么事情。</div><div>在 TCP 连接中， SIGIO 信号将会在这个时候产生：<br />l&nbsp; 在一个监听某个端口的套接字上成功的建立了一个新连接。<br />l&nbsp; 一个断线的请求被成功的初始化。<br />l&nbsp; 一个断线的请求成功的结束。<br />l&nbsp; 套接字的某一个通道（发送通道或是接收通道）被关闭。<br />l&nbsp; 套接字接收到新数据。<br />l&nbsp; 套接字将数据发送出去。</div><p style="margin: 0px 0px 10px; padding: 0px; ">l&nbsp; 发生了一个异步 I/O 的错误。</p><p style="margin: 0px 0px 10px; padding: 0px; ">一个对信号驱动 I/O 比较实用的方面是&nbsp;<span style="color: #5500ff; ">NTP</span>（网络时间协议 Network Time Protocol）服务器，它使用 UDP。这个服务器的主循环用来接收从客户端发送过来的数据报数据包，然后再发送请求。对于这个服务器来说，记录下收到每一个数据包的具体时间是很重要的。</p><p style="margin: 0px 0px 10px; padding: 0px; ">因为那将是返回给客户端的值，客户端要使用这个数据来计算数据报在网络上来回所花费的时间。图 6-8 表示了怎样建立这样的一个 UDP 服务器。</p><p style="margin: 0px 0px 10px; padding: 0px; ">&nbsp;</p><p style="margin: 0px 0px 10px; padding: 0px; ">&nbsp;</p><div><strong><span style="line-height: 28px; color: #5500ff; font-size: 16px; ">异步I/O模式&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//比如写操作，只需用写，不一定写入磁盘(这就是异步I/O)的好处。异步IO的好处效率高。</span></strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当我们运行在异步 I/O 模式下时，我们如果想进行 I/O 操作，只需要告诉内核我们要进行 I/O 操作，然后内核会马上返回。具体的 I/O 和数据的拷贝全部由内核来完成，我们的程序可以继续向下执行。当内核完成所有的 I/O 操作和数据拷贝后，内核将通知我们的程序。<br /><span style="color: #5500ff; ">异步 I/O 和&nbsp; 信号驱动I/O的区别是：</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、信号驱动 I/O 模式下，内核在操作可以被操作的时候通知给我们的应用程序发送SIGIO 消息。</div><p style="margin: 0px 0px 10px; padding: 0px; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、异步 I/O 模式下，内核在所有的操作都已经被内核操作结束之后才会通知我们的应用程序。<br /><img src="http://www.cppblog.com/images/cppblog_com/mysileng/5791910595775213302.jpg" width="674" height="459" alt="" /><br /></p><p style="margin: 0px 0px 10px; padding: 0px; ">转自:<a href="http://blog.163.com/xychenbaihu@yeah/blog/static/13222965520112163171778/">http://blog.163.com/xychenbaihu@yeah/blog/static/13222965520112163171778/</a></p></div></div></div><img src ="http://www.cppblog.com/mysileng/aggbug/196347.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-16 12:21 <a href="http://www.cppblog.com/mysileng/archive/2012/12/16/196347.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>孤儿进程组和终端会话  (转)</title><link>http://www.cppblog.com/mysileng/archive/2012/12/16/196346.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Sun, 16 Dec 2012 02:42:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/16/196346.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196346.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/16/196346.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196346.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196346.html</trackback:ping><description><![CDATA[<p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #333333; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ccced0; text-indent: 2em; ">孤儿进程：&nbsp;即一个其父进程已经终止的进程。&nbsp;孤儿进程由 init 进程&#8220;收养&#8221;，init 进程ID为1，因此被收养的孤儿进程的父进程便更新为1。</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #333333; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ccced0; text-indent: 2em; ">孤儿进程组：&nbsp;一个进程组中的所有进程的父进程要么是该进程组的一个进程，要么不是该进程组所在的会话中的进程。&nbsp;一个进程组不是孤儿进程组的条件是，该组中有一个进程其父进程在属于同一个会话的另一个组中。<br /></p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #333333; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ccced0; text-indent: 2em; ">GNU解释了为什么会提出孤儿进程组的概念：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; When a controlling process terminates, its terminal becomes free and a new session can be established on it. (In fact, another user could log in on the terminal.) This could cause a problem if any processes from the old session are still trying to use that terminal.<br />To prevent problems, process groups that continue running even after the session leader has terminated are marked as orphaned process groups.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; When a process group becomes an orphan, its processes are sent a SIGHUP signal. Ordinarily, this causes the processes to terminate. However, if a program ignores this signal or establishes a handler for it, it can continue running as in the orphan process group even after its controlling process terminates; but it still cannot access the terminal any more.</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #333333; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ccced0; text-indent: 2em; ">当一个终端控制进程（即会话首进程）终止后，那么这个终端可以用来建立一个新的会话。这可能会产生一个问题，原来旧的会话（一个或者多个进程组的集合）中的任一进程可再次访问这个的终端。为了防止这类问题的产生，于是就有了孤儿进程组的概念。当一个进程组成为孤儿进程组时，posix.1要求向孤儿进程组中处于停止状态的进程发送SIGHUP（挂起）信号，系统对于这种信号的默认处理是终止进程，然而如果无视这个信号或者另行处理的话那么这个挂起进程仍可以继续执行。</p><hr id="null" style="line-height: 25px; color: #333333; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ccced0; " /><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #333333; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ccced0; ">以下摘自网络：</p><p style="line-height: 25px; margin: 0px 0px 10px; padding: 0px; color: #333333; font-family: Arial, Helvetica, simsun, u5b8bu4f53; background-color: #ccced0; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 终端的问题涉及几个概念，那就是进程组，会话，作业，下面会分别进行介绍。会话包含了一系列的进程，这些进程按照不同的执行内容会组织成若干进程组，一个会话内的所有进程都必须是该会话首长进程的后代，这样就保证了这些进程都是由该会话首长进程直接或者间接开启的，只有这样的才能保证这些进程确实是在会话首长进程耳目视线之内的，同时，孤儿进程组不再受到会话首长进程的控制。<br />作业：<br />只有一个终端，但是有很多事情要同时做，或者起码分时做，不能先做完一件事再做另一件，怎么办？毕竟启动一个进程后该进程就会独占终端啊，毕竟shell会将它设置为前台进程组进程啊。这就是作业的功能，只需要在一个命令后加一个&amp;符号就可以了，比如我要执行x，那么就敲入：<br />x &amp;<br />shell的结果是：<br />[1] 1234<br />此处1234是进程的pid，而1则是作业的id，这样这个x就不占用终端了，shell可以启动其它的进程或者作业了，比如又启动了作业2：<br />[2] 4321<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 此时想起作业1需要使用一下终端来输入一些信息了，那么就使用：fg %1将作业1置于前台(作业1中目前只有一个进程)，置于前台的作业如何重新放到后台呢？只需要用SIGSTOP信号停止前台使用终端的进程即可，然后该进程就放开终端的占用了<br />进程组：一个作业就是一个进程组，单独的进程可以独占一个进程组也可以加入同一会话的别的进程组，必须要满足的条件是，同一进程组的所有进程都要是一个会话的后代。所谓的进程组是为了组织作业或者组织同一类任务的。<br />控制终端：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个会话的建立者有权力申请一个控制终端，在该控制终端中可以接受标准输入，可以发送shell理解的控制快捷键，可以创建作业并且使用会话头进程提供的作业控制功能。控制终端只能由会话头进程创建，并且控制终端是独占的，只要有一个进程将一个终端当成了控制终端，别的进程不管它是谁都不能这么做了，tty_open中的最后有下面几行代码<br />if (!noctty &amp;&amp;<br />&nbsp;&nbsp;&nbsp; current-&gt;signal-&gt;leader &amp;&amp;<br />&nbsp;&nbsp;&nbsp; !current-&gt;signal-&gt;tty &amp;&amp;<br />&nbsp;&nbsp;&nbsp; tty-&gt;session == 0) {<br />&nbsp;&nbsp;&nbsp; task_lock(current);<br />&nbsp;&nbsp;&nbsp; current-&gt;signal-&gt;tty = tty;<br />&nbsp;&nbsp;&nbsp; task_unlock(current);<br />&nbsp;&nbsp;&nbsp; current-&gt;signal-&gt;tty_old_pgrp = 0;<br />&nbsp;&nbsp;&nbsp; tty-&gt;session = current-&gt;signal-&gt;session;&nbsp; //设置session<br />&nbsp;&nbsp;&nbsp; tty-&gt;pgrp = process_group(current);<br />}<br />可见别的进程是无权申请控制终端的。<br />&nbsp;&nbsp;&nbsp;&nbsp; 这个控制终端平时给谁用呢？最不容被怀疑的会话首长申请了终端，因为如果连他都值得怀疑的话，后面的属于他的孩子进程们都值得怀疑了，首长申请的终端就是给这些孩子们用的，首长将这些孩子们分成了若干的进程组，指定一个组为前台进程组，只有这个前台进程组的进程才能使用控制终端。bash一般会作为会话首长存在，bash将为一个执行的命令都创建一个进程组，它在接受一个命令准备执行的时候会将该进程设置为前台进程组，它在接受了命令行后加&amp;的命令时，会创建一个作业，并且将它设定为后台进程组，那么此时前台是谁呢，是bash自己哦。后台进程不能使用终端，如果使用&amp;执行了内部带有诸如getchar之类函数的进程，那么其将会收到SIGTTIN信号，不过可以使用fg命令将这类进程提到前台。<br />控制进程：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 很显然，首先控制进程是一个会话的首长进程，另外即使是会话首长也只能通过终端来控制别的进程，所谓的控制就是发送信号而不是操作内存之类的，这也是进程间通信的一种方式。因此所谓的控制进程就是申请到控制终端的进程。<br />孤儿进程组：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有孤儿进程，对应的也有孤儿进程组的概念。为何引入这个概念以及这个概念的引入需要OS的实现者作些什么呢？先看两个前提，首先，posix用一个session的概念来描述一次用户的登录以及该用户在此次登录后的操作，然后用作业的概念描述不同操作的内容，最后才用进程的概念描述不同操作中某一个具体的工作；其次，unix最初将所有的进程组织成了树的形式，这样就便于追踪每个进程也便于管理(想想看，人类政治社会也是一个类似树形结构：君主专制，两院制等)。有了上述两个前提事情就很明白了，一切都是为了便于管理，一切都是为了登录用户的安全，即此次登录用户的作业是不能被下个登录用户所控制的，即使它们的用户名一致也是不行的，因此所谓的孤儿进程组简单点说就是脱离了创造它的session控制的，离开其session眼线的进程组，unix中怎样控制进程，怎样证明是否在自己的眼线内，那就是树形结构了，只要处于以自己为根的子树的进程就是自己眼线内的进程，这个进程就是受到保护的，有权操作的，而在别的树枝上的进程原则上是触动不得的(又想说说windows的远程线程创建了，可是说的话还要接着说其复杂的令牌机制，否则windows粉丝不服气，所以不说了罢)，unix中建立进程使用fork，自然地这么一&#8220;叉子&#8221;就形成了自己的一个树枝，当然在自己眼线了，一般对于登录用户而言一个会话起始于一次login之后的shell，只要该用户不logout，在该终端的shell上执行的所有的非守护进程都是该shell的后代进程，因此它们组成一个会话，全部在shell的眼线中，一个会话终止于会话首长的death。现在考虑一下终端上的shell退出后的情景，按照规定，该终端上所有的进程都过继给了别的进程，大多数情况是init进程，然后紧接着另外一个用户登录了这个终端或者知道前一个登录用户密钥的另一个有不好念头的人登录了该终端，当然为其启动的shell创建了一个新的session，由于之前登录的用户已退出，现在登录的用户由于之前用户的进程组都成了孤儿进程组，所以它再有恶意也不能控制它们了，那些孤儿进程组中的成员要么继续安全的运行，要么被shell退出时发出的SIGHUP信号杀死。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;POSIX的规定是铁的纪律，而unix或者linux的不管是内核还是shell的实现则是一种遵守纪律的方式，铁的纪律要求作业控制要以session为基本，就是说不能操作别的session内的进程组，所以类似fg和bg等命令就不能操作孤儿进程，因此如果由于后台进程组由于读写终端被SIGSTOP信号停了，而后它又成了孤儿进程组的成员，那怎么办？别的session的作业控制命令又不能操作它，即使ps -xj找到了它然后手工发送了SIGCONT，那么它还是没法使用终端，这是POSIX的另一个纪律要求的，只有唯一和终端关联的session中的前台进程组的进程可以使用终端，因此只要有一个shell退出了，最好的办法就是将其session内的所有的进程都干掉，因此SIGHUP的原意就是如此，但是完全可以忽略这个信号或者自己定义对该信号的反应。POSIX的基本限制就是session的ID是不能设置的，因为它是受保护的基本单位，但是进程组的ID是可以设置的，毕竟它只是区分了不能的作业，最后进程的PID也是不能设置的，因为它是进程的内秉属性，形成树形进程结构的关键属性。<br />&nbsp;&nbsp;&nbsp;&nbsp; POSIX对孤儿进程组的定义：组中没有一个进程的父进程和自己属于同一个会话但是不同进程组的。<br /><br />转自&nbsp;<a href="http://xingyunbaijunwei.blog.163.com/blog/static/765380672011112633634628/">http://xingyunbaijunwei.blog.163.com/blog/static/765380672011112633634628/</a></p><img src ="http://www.cppblog.com/mysileng/aggbug/196346.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-16 10:42 <a href="http://www.cppblog.com/mysileng/archive/2012/12/16/196346.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>进程/线程 同步机制</title><link>http://www.cppblog.com/mysileng/archive/2012/12/14/196247.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Fri, 14 Dec 2012 03:46:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/14/196247.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196247.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/14/196247.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196247.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196247.html</trackback:ping><description><![CDATA[<p style="margin-top: 10px; margin-bottom: 10px; background-color: #ffffff; "><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">1 什么时候需要同步？</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; "><br /></div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">2 在linux中， 线程同步机制有哪些？各适用在怎样的条件？进程同步有哪些？对应的数据类型、API 各有哪些？</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">在当前的POSIX标准中<span style="color: red; ">有三种线程同步机制</span>，它们分别是：互斥量、读写锁、条件变量。</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">关于<span style="color: red; ">进程同步机制，POSIX定义了一种信号灯</span>，而system V 定义了另外一种信号灯。</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">----------------------------------------------------------------------&nbsp;<br />线程同步</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; "><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23px; background-color: #ffffff; ">(1)、互斥量（mutex）</p><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23px; background-color: #ffffff; ">　　互斥量本质上是一把锁，在访问共享资源前对互斥量进行加锁，在访问完成后释放互斥量上的锁。</p><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23px; background-color: #ffffff; ">　　对互斥量进行加锁以后，任何其它试图再次对互斥量加锁的线程将会被阻塞直到当前线程释放该互斥锁。如果释放互斥锁时有多个线程阻塞，所有在该互斥锁上的阻塞线程都会变成可运行状态，第一个变为运行状态的线程可以对互斥量加锁，其它线程将会看到互斥锁依然被锁住，只能回去再次等待它重新变为可用。在这种情况下，每次只有一个线程可以向前执行。</p></div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">pthread_mutex_t&nbsp;</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">pthread_mutex_init();</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">pthread_mutex_lock();</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">pthread_mutex_unlock();</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">pthread_mutex_destroy();</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; "></div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">(2)<span style="background-color: #ffffff; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23px; ">、读写锁</span><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23px; background-color: #ffffff; ">　　读写锁与互斥量类似，不过读写锁允许更高的并行性。互斥量要么是锁住状态要么是不加锁状态，而且一次只有一个线程可以对其加锁。</p><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23px; background-color: #ffffff; ">　　读写锁可以由三种状态：<strong>读模式下加锁状态</strong>、<strong>写模式下加锁状态</strong>、<strong>不加锁状态</strong>。一次只有一个线程可以占有写模式的读写锁，但是多个线程可以同时占有读模式的读写锁。</p><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23px; background-color: #ffffff; ">　　在读写锁是<strong>写加锁状态</strong>时，在这个锁被解锁之前，所有试图对这个锁加锁的线程都会被阻塞。当读写锁在<strong>读加锁状态</strong>时，所有试图以读模式对它进行加锁的线程都可以得到访问权，但是如果线程希望以写模式对此锁进行加锁，它必须阻塞直到所有的线程释放读锁。虽然读写锁的实现各不相同，但当读写锁处于读模式锁住状态时，如果有另外的线程试图以写模式加锁，读写锁通常会阻塞随后的读模式锁请求。这样可以避免读模式锁长期占用，而等待的写模式锁请求一直得不到满足。</p><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23px; background-color: #ffffff; ">　　<strong>读写锁非常适合于对数据结构读的次数远大于写的情况</strong>。当读写锁在写模式下时，它所保护的数据结构就可以被安全地修改，因为当前只有一个线程可以在写模式下拥有这个锁。当读写锁在读状态下时，只要线程获取了读模式下的读写锁，该锁所保护的数据结构可以被多个获得读模式锁的线程读取。</p><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23px; background-color: #ffffff; ">　　<strong>读写锁也叫做共享-独占锁</strong>，当读写锁以读模式锁住时，它是以共享模式锁住的；当他以写模式锁住时，它是以独占模式锁住的。</p></div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">pthread_rwlock_t</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">pthread_rwlock_init();</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">pthread_rwlock_rdlock();</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">pthread_rwlock_wrlock();</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">pthread_rwlock_unlock();</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">pthread_rwlock_destroy();</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; "></div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">(3)&nbsp;<span style="background-color: #ffffff; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23px; ">、条件变量(condition)和监视器(monitor)</span><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23px; background-color: #ffffff; ">　　条件变量与互斥量一起使用时，允许线程以无竞争的方式等待特定的条件发生。</p><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23px; background-color: #ffffff; ">　　条件本身是由互斥量保护的。线程在改变条件状态前必须首先锁住互斥量，其它线程在获得互斥量之前不会察觉到这种改变，因此必须锁定互斥量以后才能计算条件。</p></div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">pthread_cond_t</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">pthread_cond_init();</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">pthreadf_cond_wait();</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">pthread_cond_signal();</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">pthread_cond_destroy();<br /></div><div style="word-wrap: break-word; margin: 0px; background-color: #fffcf3; "><font face="宋体, Arial"><span style="font-size: 12px; line-height: 1.5;">----------------------------------------------------------------------</span></font><br /><font face="宋体, Arial"><span style="font-size: 12px; line-height: 1.5;">进程同步&nbsp;</span></font><br /><div><span style="font-size: 12px; line-height: 18px;">信号量(Semaphore)，有时被称为信号灯，是在多线程环境下使用的一种设施，是</span><span style="font-size: 12px; line-height: 18px; ">可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前</span><span style="font-size: 12px; line-height: 18px; ">，线程必须获取一个信号量；一旦该关键代码段完成了，那么该线程必须释放信</span><span style="font-size: 12px; line-height: 18px; ">号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。为</span><span style="font-size: 12px; line-height: 18px; ">了完成这个过程，需要创建一个信号量VI，然后将Acquire Semaphore VI以及</span><span style="font-size: 12px; line-height: 18px; ">Release Semaphore VI分别放置在每个关键代码段的首末端。确认这些信号量VI</span><span style="font-size: 12px; line-height: 18px; ">引用的是初始创建的信号量。<br /><br /></span></div></div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">POSIX信号灯：</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">sem_t</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">sem_open();</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">sem_init();</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">sem_wait();</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">sem_post();</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">sem_close();</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">sem_unlink();</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; "></div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">SysV信号灯：</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">semget();</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">semop();</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">semctl();<br /></div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">3 线程同步机制和进程同步机制有什么区别？哪个使用的范围更大？</div><div style="font-family: 宋体, Arial; font-size: 12px; line-height: 1.5; word-wrap: break-word; margin: 0px; background-color: #fffcf3; ">显然进程同步机制可以用于线程同步，而线程同步机制不能用于进程同步。</div><br /><br /></p><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23px; background-color: #ffffff; "><br /></p><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 23px; background-color: #ffffff; "><br /></p><img src ="http://www.cppblog.com/mysileng/aggbug/196247.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-14 11:46 <a href="http://www.cppblog.com/mysileng/archive/2012/12/14/196247.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于分离线程（转）</title><link>http://www.cppblog.com/mysileng/archive/2012/12/14/196244.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Fri, 14 Dec 2012 03:01:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/14/196244.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196244.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/14/196244.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196244.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196244.html</trackback:ping><description><![CDATA[<p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">线程的分离状态决定一个线程以什么样的方式来终止自己。<br />线程的默认属性，一般是非分离状态，<br />这种情况下，原有的线程等待创建的线程结束。<br />只有当pthread_join（）函数返回时，创建的线程才算终止，才能释放自己占用的系统资源。<br />而分离线程没有被其他的线程所等待，自己运行结束了，线程也就终止了，马上释放系统资源。<br />程序员应该根据自己的需要，选择适当的分离状态。</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">关于分离线程的一种用法（转）</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">讲到分离线程，先得从僵尸进程讲起（抱歉，确实不知道线程是否有僵尸一说）。</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">关于僵尸进程：一般情况下进程终止的时候，和它相关的系统资源也并不是主动释放的，而是进入一种通常称为&#8220;僵尸&#8221;(zombie)的状态。它所占有 的资源一直被系统保留，直到它的父进程（如果它直接的父进程先于它去世，那么它将被init进程所收养，这个时候init就是它的父进程）显式地调用 wait系列函数为其&#8220;收尸&#8221;。为了让父进程尽快知道它去世的消息，它会在它死去的时候通过向父进程发送SIGCHLD信号的方式向其&#8220;报丧&#8221;。</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">所以一旦父进程长期运行，而又没有显示wait或者waitpid，同时也没处理SIGCHLD信号，这个时候init进程，就没办法来替子进程来收尸。这个时候，子进程就真的成了&#8221;僵尸&#8220;了。</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">同理：</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">如果一个线程调用了这个函数，那么当这个线程终止的时候，和它相关的系统资源将被自动释放，系统不用也不能用pthread_join()等待其退 出。有的时候分离线程更好些，因为它潜在地减少了一个线程回收的同步点，并且pthread_join()这个API确实也是相当地难用。</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; ">为了让主线程省去去子线程收尸的过程，可以使用</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; "><span style="color: #0000ff; ">int</span>&nbsp;<span style="color: #ff0000; ">pthread_detach</span><span style="color: #0000cc; ">(</span><span style="color: #ff0000; ">pthread_t</span>&nbsp;thread<span style="color: #0000cc; ">)</span><span style="color: #0000cc; ">;</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; "><span style="color: #000000; ">来让子线程处于分离状态，就不需要父线程再pthread_join了。</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; "><span style="color: #000000; ">我们来看一种分离线程的用法。上次别人问道一种情况，我发现必须要分离子线程：</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; "><div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all; "><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">void</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;task1(</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">*</span><span style="color: #000000; ">);<br /><br /></span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;usr();<br /><br /></span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;p1;<br /><br /></span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;main()<br />{<br />p1</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;<br />usr();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">调用这个认为是你的触发函数</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;getchar();<br /></span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">;<br />}<br /><br /></span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;usr()<br />{<br />pthread_t&nbsp;&nbsp;pid1;<br />pthread_attr_t&nbsp;attr;<br /></span><span style="color: #008000; ">/*</span><span style="color: #008000; ">这里做你的事情</span><span style="color: #008000; ">*/</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">(p1</span><span style="color: #000000; ">==</span><span style="color: #000000; ">0</span><span style="color: #000000; ">)<br />{&nbsp;&nbsp;&nbsp;&nbsp;pthread_attr_init(</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">attr);<br />pthread_attr_setdetachstate(</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">attr,&nbsp;PTHREAD_CREATE_DETACHED);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">因为你的线程不便于等待的关系，设置为分离线程吧&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_create(</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">pid1,&nbsp;</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">attr,&nbsp;task1,&nbsp;NULL);<br /><br />}<br /><br />}<br /><br /></span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;task1(</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">arg1)<br />{<br />p1</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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">让子线程不会被多次调用</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;i</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;<br />printf(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">thread1&nbsp;begin./n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br /></span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">(i</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;i</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">100</span><span style="color: #000000; ">;i</span><span style="color: #000000; ">++</span><span style="color: #000000; ">)<br />{<br />sleep(</span><span style="color: #000000; ">2</span><span style="color: #000000; ">);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />printf(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">At&nbsp;thread1:&nbsp;i&nbsp;is&nbsp;%d/n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,i);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />usr();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">继续调用</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;}<br />pthread_exit();<br />}<br />&nbsp;</span></div></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; "><span style="color: #000000; ">我 们看到，在这里task1这个线程函数居然会多次调用其父线程里的函数，显然usr函数里，我们无法等待task1结束，反而task1会多次调用 usr，一旦我们在usr里pthread_join，则在子线程退出前，有多个usr函数会等待，很浪费资源。所以，此处，将task1设置为分离线程 是一种很好的做法。</span></p><img src ="http://www.cppblog.com/mysileng/aggbug/196244.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-14 11:01 <a href="http://www.cppblog.com/mysileng/archive/2012/12/14/196244.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于system()实现中阻塞sigchld信号的问题（转帖）</title><link>http://www.cppblog.com/mysileng/archive/2012/12/14/196243.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Fri, 14 Dec 2012 02:58:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/14/196243.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196243.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/14/196243.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196243.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196243.html</trackback:ping><description><![CDATA[<div fc05="" fc11="" nbw-blog="" ztag=""  js-fs2"="" style="word-wrap: break-word; margin: 0px; line-height: 1.5; font-family: 宋体, Arial; font-size: 12px; background-color: #f5f7f8;"><span style="word-wrap: break-word; line-height: normal; font-family: verdana, arial, sans-serif; font-size: 13px; "><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; "><span style="word-wrap: break-word; line-height: normal; ">这是一个网友的提问：</span></div><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; "><span style="word-wrap: break-word; line-height: normal; "><br style="word-wrap: break-word; " /></span></div>在 UNIX的system（）函数实现过程中，要求在父进程中忽略掉SIGINT和SIGQUIT信号，但是要将SIGCHLD信号阻塞（在子进程中将 SIGINT和SIGQUIT信号设为默认，SIGCHLD信号解锁）。子进程执行完毕后，在父进程中调用waitpid（pid_t, &amp;state, 0）。问题：&nbsp;<br style="word-wrap: break-word; " />1、若父进程已被waitpid阻塞，在子进程返回时，此时在父进程中SIGCHLD被阻塞（BLOCK），父进程收不到SIGCHLD信号，waitpid（）函数能否正确返回，收集到子进程的信息？&nbsp;<br style="word-wrap: break-word; " />2、 waitpid若能正确完成，在以后父进程中，将SIGCHLD信号UNBLOCK，用sigprocmask（）函数解锁，书上说，在 sigprocmask（）函数返回以前，会将以前阻塞的信号发送给进程，父进程是否还能收到SIGCHLD信号？若能收到何必在开始时将SIGCHLD 进程阻塞。&nbsp;</span><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; "><span style="word-wrap: break-word; line-height: normal; font-family: verdana, arial, sans-serif; font-size: 13px; "><br style="word-wrap: break-word; " /></span></div><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; "><span style="word-wrap: break-word; line-height: normal; font-family: verdana, arial, sans-serif; font-size: 13px; "><br style="word-wrap: break-word; " /></span></div><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; "><span style="word-wrap: break-word; line-height: normal; font-size: 13px; "><span style="word-wrap: break-word; line-height: 23px; font-family: simsun; font-size: 14px; ">简单的对这个问题的解释是</span><span style="word-wrap: break-word; line-height: 23px; font-family: simsun; font-size: 14px; color: red;">wait及其变体并不是通过sigchld信号来知道子进程状态的。</span></span></div><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; "><span style="word-wrap: break-word; line-height: 23px; ">sigprocmask 阻塞的是有signal或sigaction设置的信号处理程序，即带有SIGCHLD_Handle()等处理函数。wait不是靠接收sigchld 信号获得子进程的退出状态的，如果进程中同时设置了signal和wait，则子进程退出后发出sigchld信号，交到signal的信号处理程序处 理，wait接收到子进程退出状态。<br style="word-wrap: break-word; " />只是接收sigchld，而不调用wait还是会使子进程僵死的。一般的只有调用wait才能使子进程不成为僵死进程（除了2次fork 等或其他一些手段）。</span></div><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; "><span style="word-wrap: break-word; line-height: 23px; "><br style="word-wrap: break-word; " /></span></div><div style="word-wrap: break-word; margin: 0px; line-height: 1.5; "><span style="word-wrap: break-word; line-height: 23px; ">概括下：waitpid不是依靠SIGCHLD是否到达来判断子进程是否退出，但是如果设置了SIGCHLD的处理函数，那么就需要等待SIGCHLD信号 的发生并完成信号处理函数，waitpid才能接收到子进程的退出状态。在APUE中的system()实现中阻塞了SIGCHLD信号，但是并没有设置 信号处理函数，所以waitpid在阻塞了SIGCHLD的情况下依然能正常返回，因为SIGCHLD在未设置信号处理函数的情况下不会影响到 waitpid的工作。至于为什么要阻塞SIGCHLD信号呢？那就是为了防止其他程序（main除了会调用system还会使用其他程序）设置了 SIGCHLD的信号处理函数，如果其他程序设置了SIGCHLD信号处理函数，在waitpid等待子程序的返回前，要去处理SIGCHLD信号处理程 序，如果阻塞了该信号，就不会去处理该信号处理程序，防止多余信息在system()中的出现。</span></div></div><img src ="http://www.cppblog.com/mysileng/aggbug/196243.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-14 10:58 <a href="http://www.cppblog.com/mysileng/archive/2012/12/14/196243.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>慢系统调用与信号中断(转)</title><link>http://www.cppblog.com/mysileng/archive/2012/12/10/196146.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Mon, 10 Dec 2012 08:51:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/10/196146.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196146.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/10/196146.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196146.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196146.html</trackback:ping><description><![CDATA[<span style="background-color: #bcd3e5; "><div style="color: #464646; font-family: simsun; font-size: 14px; line-height: 21px; "><strong></strong></div></span><span class="Apple-style-span" style="font-family: Arial; line-height: 26px; background-color: #ffffff; "><p id="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">早期的Unix系统，如果进程在一个&#8216;慢&#8217;系统调用中阻塞时，捕获到一个信号，这个系统调用被中断，调用返回错误，<strong>设置errno为EINTR</strong>。系统调用被分为<a name="baidusnap0" style="color: #ca0000; text-decoration: none; width: 20px; height: 20px; text-indent: 20px; background-image: url(http://www.cppblog.com/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); background-repeat: no-repeat no-repeat; "></a><span style="color: black; background-color: #ffff66; ">慢系统调用</span>和其他两大类别。</p><p id="aeaoofnhgocdbnbeljkmbjdmhbcokfdb-mousedown" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: black; background-color: #ffff66; ">慢系统调用</span>可以被永久阻塞，包括<strong><span id="" style="color: #ff0000; ">以下几个类别</span></strong>：</p><p id="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （1）读写&#8216;慢&#8217;设备（包括pipe，终端设备，网络连接等）。读时，数据不存在，需要等待；写时，缓冲区满或其他原因，需要等待。读写磁盘文件一般不会阻塞。</p><p id="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （2）当打开某些特殊文件时，需要等待某些条件，才能打开。例如：打开中断设备时，需要等到连接设备的modem响应才能完成。</p><p id="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （3）pause和wait函数。pause函数使调用进程睡眠，直到捕获到一个信号。wait等待子进程终止。</p><p id="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （4）某些ioctl操作。</p><p id="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （5）某些IPC操作。</p><p id="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">&nbsp;&nbsp;&nbsp; 有些情况下，即使操作被<a name="baidusnap3" style="color: #ca0000; text-decoration: none; width: 20px; height: 20px; text-indent: 20px; background-image: url(http://www.cppblog.com/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif); background-repeat: no-repeat no-repeat; "></a><span style="color: black; background-color: #ff9999; ">信号中断</span>，还是要继续执行该操作，即需要重启该操作。那么，程序需要检查系统调用的错误类型是否为EINTR，如果是，表明系统调用被中断，则重新启动操作。典型代码如下所示：</p><p id="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span id="" style="color: #0000ff; ">again:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((n = read(fd, buf, BUFFSIZE)) &lt; 0) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (errno == EINTR)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; goto again;&nbsp;&nbsp;&nbsp;&nbsp; /* just an interrupted system call */<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* handle other errors */<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }</span></p><p id="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">&nbsp;&nbsp;&nbsp; 4.2BSD为了简化程序的操作，提供了自动重启某些被中断系统调用的功能，这些系统调用包括ioctl，read，readv，write，writev，wait，waitpid。前五个函数当它们操作慢设备时，才会被中断。这可能给那些不希望自动重启这些系统调用的应用带来麻烦，所以4.3BSD允许进程在指定信号上关闭此功能。</p><p id="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">&nbsp;&nbsp;&nbsp; POSIX.1允许实现重新启动系统调用，但没有强制要求。SUS给sigaction增加了一个XSI扩展标记SA_RESTART，要求被该<span style="color: black; background-color: #ff9999; ">信号中断</span>的系统调用被自动重启。</p><p id="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">&nbsp;</p><div id="" style="line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; "><strong><span id="" style="font-size: 20px; ">别忘了--要处理被中断的系统调用</span></strong></div><p id="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">一般慢速系统调用基本规则是：当阻塞于某个慢系统系统调用的一个进程捕获某个信号且相应信号处理函数返回时，该系统调用可能要返回</p><p id="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">ENINTR错误。</p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">&nbsp;</p><p id="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">问:linux会重启某些被中断的系统调用吗？</p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">&nbsp;</p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">处理的例子：</p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; "></p><div style="line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; "><div><div></div></div></div><p id="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">for( ; ;) {<br />&nbsp;&nbsp;&nbsp;&nbsp; if (connfd = accept(listenfd, (SA *) &amp;cliaddr, &amp;clilen)) &lt; 0)&nbsp;<br />&nbsp;&nbsp;&nbsp; {<br /><strong><span id="" style="color: #ff0000; ">&nbsp;&nbsp;&nbsp; if (errno == EINTR)</span><br /><span style="color: #ff0000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;</span><br /></strong>&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; else<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; errsys("accept error");<br />&nbsp;&nbsp;&nbsp; }<br />}</p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; "></p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">&nbsp;</p><p id="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; "><strong>在tcp socket 中,connect()被中断后是不能被重启的</strong>？如何处理呢</p><p id="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">可以采用select来等待连接完成</p><p id="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">&nbsp;</p><p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; "><strong><span id="" style="font-size: 20px; ">系统调用被<span style="color: black; background-color: #ff9999; ">信号中断</span>和自动重启动</span></strong></p><p id="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; line-height: 20px; color: #3d5d2b; font-family: Georgia; letter-spacing: 2px; background-color: #cceda8; ">&nbsp;<span id="" style="font-family: 黑体; ">&nbsp;&nbsp; 当进程正在执行一个系统调用时，如果被<span style="color: black; background-color: #ff9999; ">信号中断</span>，这时会发生什么呢？<br /><br />当一个低速调用阻塞期间捕捉到一个信号， 则该系统调用就被中断不再继续执行。 该系统调用返回出错，起errono设置为EINTR。 因为发生信号， 进程捕捉到它， 这将是一个很好的机会来唤醒阻塞的系统调用。<br /><br />但有一个问题就是如果该系统调为read()， 正在等待终端输入， 如果被<span style="color: black; background-color: #ff9999; ">信号中断</span>的话， 难免会影响整个程序的正确性， 所以有些系统使这类系统调用自动重启动。就是一旦被某<span id="" style="color: black; background-color: #ff9999; ">信号中断</span>， 立即再启动。<br /><br />如下面的signal1函数实现:&nbsp;<br /><br />#include &lt;signal.h&gt;<br />#include "ourhdr.h"<br /><br />typedef void Sigfunc(int);<br /><br />Sigfunc *<br />signal1(int signo, Sigfunc *func)<br />{<br />struct sigaction&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; act, oact;<br /><br />act.sa_handler = func;<br />sigemptyset(&amp;act.sa_mask);<br />act.sa_flags = 0;<br /><br />if (signo ==SIGALRM)<br />{<br />#ifdef SA_INTERRUPT<br />act.sa_flags |= SA_INTERRUPT;<br />#endif<br />}<br />else<br />{<br />#ifdef SA_RESTART<br />act.sa_flags |= SA_RESTART;&nbsp;&nbsp; /*<span id="" style="color: #ff0000; ">这里对所有的信号都设置了自动再启动，唯独没有SIGALRM</span>*/<br />#endif<br />}<br /><br />if (sigaction(signo, &amp;act, &amp;oact)&lt;0)<br />return(SIG_ERR);<br />return (oact.sa_handler);<br />}<br /><br />为什么偏偏面对SIGALRM信号， 系统调用不设置自动重启动呢？ 这时为了我们方便给read等低速系统调用定时。 我们不希望它一遇到某个信号变自动重启动，也不希望它无限制的阻塞下去。 于是用alarm()进行定时， 一旦超出某个时间， 便被ALRM<span id="" style="color: black; background-color: #ff9999; ">信号中断</span>唤醒，且不再重启动。<br /><br /><br />下面这段程序用来测试上面的signal1函数， 对一个read系统调用， 如何给它定时的：<br /><br />#include &lt;signal.h&gt;<br />#include "ourhdr.h"<br />#include "10-12.c"<br /><br />#define MAXLINE 1024<br /><br />static void sig_alrm(int);<br /><br />int<br />main(void)<br />{<br />int&nbsp;&nbsp;&nbsp;&nbsp; n;<br />char line[MAXLINE];<br /><br />if (signal1(SIGALRM, sig_alrm) == SIG_ERR)<br />perror("signal");<br /><br />alarm(10);<br />if ( (n = read(STDIN_FILENO, line, MAXLINE)) &lt; 0)<br />perror("read");<br />alarm(0);<br />write(STDOUT_FILENO, line, n);<br />write(STDOUT_FILENO, "exit\n", 5);<br /><br />exit(0);<br />}<br /><br />static void<br />sig_alrm(int signo)<br />{<br />write(STDOUT_FILENO, "recieved signal -ALRM\n", 22);<br />return;<br />}<br /><br />在我的系统中， 如果调用默认的signal函数， 该read()系统调用将会自动重启动， 所谓的alarm定时也就不起作用了。</span></p></span><span style="background-color: #bcd3e5; "><div></div></span><img src ="http://www.cppblog.com/mysileng/aggbug/196146.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-10 16:51 <a href="http://www.cppblog.com/mysileng/archive/2012/12/10/196146.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>UNIX进程组，会话和作业控制(转)</title><link>http://www.cppblog.com/mysileng/archive/2012/12/09/196125.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Sun, 09 Dec 2012 06:30:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/09/196125.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/196125.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/09/196125.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/196125.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/196125.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp; &nbsp; &nbsp; &nbsp;在UNIX系统中，作业控制:允许在一个终端上启动多个作业（进程组），控制哪一个作业可以存取该终端，以及哪些作业在后台运行。一句话就是，作业控制是解决不同作业（也就是进程组）对控制终端这个资源的使用的竞争问题。作业控制作为Shell的一个特性存在，也就是说有的shell支持作业控制这个作业功能，有的不支持。linux下常用的bash是支持的作业控...&nbsp;&nbsp;<a href='http://www.cppblog.com/mysileng/archive/2012/12/09/196125.html'>阅读全文</a><img src ="http://www.cppblog.com/mysileng/aggbug/196125.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-09 14:30 <a href="http://www.cppblog.com/mysileng/archive/2012/12/09/196125.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>调用fork两次以避免僵死进程</title><link>http://www.cppblog.com/mysileng/archive/2012/12/02/195899.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Sun, 02 Dec 2012 10:12:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/12/02/195899.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/195899.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/12/02/195899.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/195899.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/195899.html</trackback:ping><description><![CDATA[<p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">如果一个进程fork一个子进程，但不要它等待子进程终止，也不希望子进程处于僵死状态直到父进程终止，实现这一要求的技巧是调用fork2次。</p><p style="margin: 0px; padding: 0px; font-family: Arial; line-height: 26px; background-color: #ffffff;">下面是实例代码：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#include&nbsp;&lt;stdio.h&gt;<br />#include&nbsp;&lt;stdlib.h&gt;<br />#include&nbsp;&lt;sys/wait.h&gt;<br /><br /><span style="color: #0000FF; ">int</span>&nbsp;main(<span style="color: #0000FF; ">void</span>)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pid_t&nbsp;pid;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>((pid&nbsp;=&nbsp;fork())&nbsp;&lt;&nbsp;0)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("error:&nbsp;fork&nbsp;error.\n");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;<span style="color: #0000FF; ">if</span>(pid&nbsp;==&nbsp;0)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>((pid&nbsp;=&nbsp;fork())&nbsp;&lt;&nbsp;0)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("error:&nbsp;fork&nbsp;error.\n");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;<span style="color: #0000FF; ">if</span>(pid&nbsp;&gt;&nbsp;0)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(0);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">/*</span><span style="color: #008000; ">&nbsp;we&nbsp;are&nbsp;the&nbsp;second&nbsp;child;&nbsp;our&nbsp;parent&nbsp;becomes&nbsp;init&nbsp;as&nbsp;soon&nbsp;as<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;our&nbsp;real&nbsp;parent&nbsp;calls&nbsp;exit()&nbsp;in&nbsp;the&nbsp;statement&nbsp;above.&nbsp;Here&nbsp;is&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;where&nbsp;we&nbsp;had&nbsp;continue&nbsp;executing&nbsp;,&nbsp;knowing&nbsp;that&nbsp;when&nbsp;we&nbsp;are&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;done,&nbsp;init&nbsp;will&nbsp;reap&nbsp;our&nbsp;status.&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">*/</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep(2);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("second&nbsp;child,&nbsp;parent&nbsp;pid&nbsp;=&nbsp;%d\n",&nbsp;getppid());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(0);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(waitpid(pid,&nbsp;NULL,&nbsp;0)&nbsp;!=&nbsp;pid)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("error,&nbsp;waitpid&nbsp;error.\n");<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(0);<br />}</div>&nbsp; &nbsp; &nbsp; 这里核心思想是，把第二个子进程的父进程换成init进程，因为init进程会立马终止僵死进程。而最开始的父进程也因为直接子进程（第一个进程）终止，不需要阻塞。<br />&nbsp; &nbsp; &nbsp;&nbsp;<span style="font-size: 14px;">第二个子进程调用sleep以保证在打印父进程ID时第一个字进程已终止。在fork之后，父子进程都可以继续执行，并且我们无法预知哪个会限制性。在fork之后，如果不是第二个子进程休眠，那么它可能比其父进程先执行，于是它打印的父进程ID将是创建它的父进程，而不是init进程。</span></p><img src ="http://www.cppblog.com/mysileng/aggbug/195899.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-12-02 18:12 <a href="http://www.cppblog.com/mysileng/archive/2012/12/02/195899.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《UNIX环境高级编程》单个源码编译方法(转)</title><link>http://www.cppblog.com/mysileng/archive/2012/11/28/195778.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Wed, 28 Nov 2012 15:36:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/11/28/195778.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/195778.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/11/28/195778.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/195778.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/195778.html</trackback:ping><description><![CDATA[<table cellspacing="0" cellpadding="0" style="word-wrap: break-word; empty-cells: show; border-collapse: collapse; table-layout: fixed; width: 808px; color: #000000; font-family: song, Verdana; font-size: 12px; background-color: #f0f3fa; "><tbody style="word-wrap: break-word; "><tr style="word-wrap: break-word; "><td id="postmessage_14660605" style="word-wrap: break-word; font-size: 14px; line-height: 1.6em; ">对于很多初学《UNIX环境高级编程》（AdvancedProgramming in the UNIX Environment,简称APUE，以下使用简称）的朋友，第一个遇到的问题可能就是该书中的源代码编译的问题。此书中差不多每个例程中，都会有这样一行源码：<br style="word-wrap: break-word; " />＃include "ourhdr.h"<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />在第二版中改为：<br style="word-wrap: break-word; " />＃include "apue.h"<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />&nbsp; &nbsp;这个头文件是作者把把每个例程中常用的标准头文件，一些常用的出错处理函数（err_**（）之类的函数）和一些常用的宏定义给整理在一个头文件中。这个可以省去在每个例程中录入较多的重复代码，这样可以减少每个例程的长度。但是，这样就给读者带来了不少麻烦。因为我们还要去搞明白如和把这个头文件编译，然后做成库文件，添加到我们的系统中。特别读于初学者，本来满怀信心的，结果在编译第一个程序的时候就出现了问题。我也没有搞明白如何把"ourhdr.h"静态的编译到系统中。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />&nbsp; &nbsp;不过，不明白如何使用"ourhdr.h"这个头文件，并不会影响我们学习APUE，也不会影响我们编译和运行每一个例程。其实，简单的想一下，如果一个C程序要能顺利的编译和运行，除了我们要语法正确等方面外，最根本的是要保证我们程序中所调用的函数以及宏等等都要有完整的来源，也就是必须包含所有调用函数和宏所在的头文件。对于一个具体的源程序，如果我们正确的包含了头文件，那么剩下的就是程序本生语法方面应该注意的事项。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />&nbsp; &nbsp;如何确定系统调用函数包含在那个头文件中呢？这在Unix/Linux系统下并非一件难事。Unix/Linux下命令man可以帮助我们找到。man命令不仅可以帮助我们查找一般命令的用法，同时提供不同层次的帮助诸如系统调用或者管理员级别的命令等等（譬如FreeBSD6.1中，man1是用户专用手册，man 2是系统调用，man 3是库函数查询等等）。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />&nbsp; &nbsp;下面我们就以APUE书中程序1-1（实现ls命令部分功能）为例，来说明如何将书中的程序改编成全部使用标准头文件的程序。其中，操作系统用的是FreeBSD6.1，经过相应的修改可以在书中所说的几个Unix系统及Linux系统中运行，我也曾在Debian Linux下成功编译和运行该程序。书中1-1.c的原始代码如下：<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /><table cellspacing="0" style="word-wrap: break-word; empty-cells: show; border-collapse: collapse; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #e3edf5; border-right-color: #e3edf5; border-bottom-color: #e3edf5; border-left-color: #e3edf5; table-layout: auto; width: 766px; "><tbody style="word-wrap: break-word; "><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; font-size: 14px; line-height: 1.6em; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #000000; border-right-color: #000000; border-bottom-color: #000000; border-left-color: #000000; overflow-x: hidden; overflow-y: hidden; ">#include&nbsp;&lt;sys/types.h&gt;<br style="word-wrap: break-word; " />#include&nbsp;&lt;dirent.h&gt;<br style="word-wrap: break-word; " />#include&nbsp;"ourhdr.h"<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />int<br style="word-wrap: break-word; " />main(int&nbsp;argc,&nbsp;char&nbsp;*argv[])<br style="word-wrap: break-word; " />{<br style="word-wrap: break-word; " />&nbsp; &nbsp; DIR&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;*dp;<br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp;struct&nbsp;dirent&nbsp; &nbsp;&nbsp;*dirp;<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp;if&nbsp;(argc&nbsp;!=&nbsp;2)<br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;err_quit("usage: ls directory_name");<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp;if&nbsp;((dp&nbsp;=&nbsp;opendir(argv[1]))&nbsp;==&nbsp;NULL)<br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;err_sys("can't open %s",&nbsp;argv[1]);<br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp;while&nbsp;((dirp&nbsp;=&nbsp;readdir(dp))&nbsp;!=&nbsp;NULL)<br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;printf("%s\n",&nbsp;dirp-&gt;d_name);<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />&nbsp; &nbsp; closedir(dp);<br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp;exit(0);<br style="word-wrap: break-word; " />}</td></tr></tbody></table><br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />&nbsp;&nbsp;从书后面的附录中可以看到"ourhdr.h"的内容比较多，包含了比较多的常用头文件，一些宏定义和一些常用函数和出错函数的定义。其实，对于每一个具体的程序，我们只需要找到该程序中用到的头文件即可。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />&nbsp; &nbsp; 该1-1.c中所用到的系统函数调用有：opnedir()，readdir()，printf()，closedir()和exit()。<br style="word-wrap: break-word; " />其中，对于常用的函数prinft()和exit()，它们所在的头文件一般都知道，分别是&lt;stdio.h&gt;和&lt;stdlib.h&gt;。而对于opnedir()，readdir()和closedir()，我们可以通过man opendir，man readdir，manclosedir得到这三个关于目录操作的函数所在的头文件都是：&lt;sys/types.h&gt;和&lt;dirent.h&gt;。这两个头文件在源程序中也已经列出。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />&nbsp; &nbsp;其次，1-1.c中还用到了作者自定义的两个函数：err_quit()和err_sys()。这两个函数主要使用来进行出错处理的。当然，使用这两个函数对错误信息的处理是比较完善的。但是，作为我们学习来讲，了解程序的核心功能是首要的，我们可以将出错处理简化一点，即当遇到错误的时候，我们只简单的使用printf()函数来提示一下有错误发生。当然，用printf()来进行出错处理并不是一种很合理的方法，而且往往我们看不到更关键的错误信息，但对于我们仅仅作为学习来用还是可以接受的。毕竟我们要理解的核心部分是程序的功能实现，出错处理在于其次。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />&nbsp; &nbsp;通过以上的说明，我们可以将1-1.c修改为如下内容：<br style="word-wrap: break-word; " /><table cellspacing="0" style="word-wrap: break-word; empty-cells: show; border-collapse: collapse; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #e3edf5; border-right-color: #e3edf5; border-bottom-color: #e3edf5; border-left-color: #e3edf5; table-layout: auto; width: 766px; "><tbody style="word-wrap: break-word; "><tr style="word-wrap: break-word; "><td style="word-wrap: break-word; font-size: 14px; line-height: 1.6em; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #000000; border-right-color: #000000; border-bottom-color: #000000; border-left-color: #000000; overflow-x: hidden; overflow-y: hidden; ">#include&nbsp;&lt;sys/types.h&gt;<br style="word-wrap: break-word; " />#include&nbsp;&lt;dirent.h&gt;<br style="word-wrap: break-word; " />#include&nbsp;&lt;stdio.h&gt;<br style="word-wrap: break-word; " />#include&nbsp;&lt;stdlib.h&gt;<br style="word-wrap: break-word; " />int&nbsp;main(int&nbsp;argc,&nbsp;char*&nbsp;argv[])<br style="word-wrap: break-word; " />{<br style="word-wrap: break-word; " />&nbsp; &nbsp; DIR&nbsp;*dp;<br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp;struct&nbsp;dirent&nbsp;*dirp;<br style="word-wrap: break-word; " />&nbsp; &nbsp;<br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp;if(argc&nbsp;!=&nbsp;2)<br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp;{<br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;printf("You need input the directory name.\n");<br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;exit(1);&nbsp;&nbsp;<br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp;}<br style="word-wrap: break-word; " />&nbsp; &nbsp;<br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp;if((dp&nbsp;=&nbsp;opendir(argv[1]))&nbsp;==&nbsp;NULL)<br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp;{<br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;printf("cannot open %s\n",&nbsp;argv[1]);<br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;exit(1);&nbsp; &nbsp;<br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp;}<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp;while&nbsp;((dirp&nbsp;=&nbsp;readdir(dp))&nbsp;!=&nbsp;NULL)<br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;printf("%s\n",&nbsp;dirp-&gt;d_name);<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />&nbsp; &nbsp; closedir(dp);<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />&nbsp; &nbsp;&nbsp;exit(0);<br style="word-wrap: break-word; " />}<br style="word-wrap: break-word; " /></td></tr></tbody></table><br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />&nbsp;&nbsp;这样修改后的程序已经与作者的头文件"ourhdr.h"没有关系，可以单独的进行编译。我使用的是root用户，执行命令：<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " /># gcc 1-1.c&nbsp;&nbsp;//生成目标文件a.out<br style="word-wrap: break-word; " />或者<br style="word-wrap: break-word; " />＃ gcc -o 1-1 1-1.c&nbsp;&nbsp;//生成目标文件1-1<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />&nbsp; &nbsp; 没有任何错误和警告，说明编译成功。这时我们执行生成的目标文件：<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />＃ ./a.out /home<br style="word-wrap: break-word; " />或者<br style="word-wrap: break-word; " />＃ ./1-1 /home<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />&nbsp; &nbsp; 则会列出/home路径下的所有文件，包括目录(.)和(..)。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />&nbsp; &nbsp;通过这样的方法，基本上我们可以将该书中所有的例程修改成不包含"ourhdr.h"的程序。这样，我们就可以单独的编译每一个例程，而不用顾及作者所给的杂凑的头文件。同时这种比较笨的方法，反而有利于帮助我们了解不同系统调用所对应的头文件，对于学习来说，这应该是一件好事。<br style="word-wrap: break-word; " /><br style="word-wrap: break-word; " />欢迎交流，欢迎自由转载，但请注明CU链接或本人CU Blog链接：<br style="word-wrap: break-word; " /><a href="http://blog.chinaunix.net/u/33048/showart_343553.html" target="_blank" style="word-wrap: break-word; color: #336699; ">http://blog.chinaunix.net/u/33048/showart_343553.html</a></td></tr></tbody></table><img src ="http://www.cppblog.com/mysileng/aggbug/195778.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-11-28 23:36 <a href="http://www.cppblog.com/mysileng/archive/2012/11/28/195778.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>