﻿<?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++博客-I smell magic in the air-随笔分类-多线程</title><link>http://www.cppblog.com/izualzhy/category/18146.html</link><description>坚持 相信自己</description><language>zh-cn</language><lastBuildDate>Sun, 01 Apr 2012 06:07:43 GMT</lastBuildDate><pubDate>Sun, 01 Apr 2012 06:07:43 GMT</pubDate><ttl>60</ttl><item><title>pthread多线程学习笔记六线程属性篇</title><link>http://www.cppblog.com/izualzhy/archive/2011/11/14/160123.html</link><dc:creator>izualzhy</dc:creator><author>izualzhy</author><pubDate>Mon, 14 Nov 2011 14:47:00 GMT</pubDate><guid>http://www.cppblog.com/izualzhy/archive/2011/11/14/160123.html</guid><wfw:comment>http://www.cppblog.com/izualzhy/comments/160123.html</wfw:comment><comments>http://www.cppblog.com/izualzhy/archive/2011/11/14/160123.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/izualzhy/comments/commentRss/160123.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/izualzhy/services/trackbacks/160123.html</trackback:ping><description><![CDATA[<p>pthread多线程学习笔记六线程属性篇 <p>其实线程属性我看明白的很少，因为属性很多，很多都永不到，很多虽然看了却没法试验下，因此不知道对错。感觉关于多线程有句话说的很对，有很多多线程的程序，只有在多个机器，多个系统上都试验过，才知道对不对，错在哪里。 <p>在/usr/include/pthread.h里可以看到一堆关于set or get attr的函数，大概全是这个样子的：pthread_attr_set*() 或者pthread_attr_get*(); <p>想了下，先从一个普通例子开始说起：</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #cc6633">#include</span> &lt;stdio.h&gt;<br><br><span style="color: #cc6633">#include</span> &lt;unistd.h&gt;<br><br><span style="color: #0000ff">int</span> main()<br><br>{<br><br><span style="color: #0000ff">const</span> size_t asize = (8192*1024+1024*1024*2)/<span style="color: #0000ff">sizeof</span>(<span style="color: #0000ff">int</span>);<br><br><span style="color: #008000">/*const size_t asize = 8388608/sizeof(int);*/</span><br><br>printf(<span style="color: #006080">"heap:\n"</span>);<br><br><span style="color: #0000ff">int</span> *parray;<br><br>parray = malloc(asize*<span style="color: #0000ff">sizeof</span>(<span style="color: #0000ff">int</span>));<br><br>parray[asize-1] = 1;<br><br>printf(<span style="color: #006080">"stack:\n"</span>);<br><br><span style="color: #0000ff">int</span> array[asize];<br><br>printf(<span style="color: #006080">"%u\n"</span>,asize);<br><br>array[asize-1]=1;<br><br><span style="color: #0000ff">return</span> 0;<br><br>}<br><br></pre><br></div>
<p>程序输出：
<p>heap:
<p>stack:
<p>段错误
<p>为什么会这样?因为每个进程的栈大小是有限制的，例如我的：
<p>$ ulimit -a
<p>core file size (blocks, -c) 0
<p>data seg size (kbytes, -d) unlimited
<p>scheduling priority (-e) 20
<p>file size (blocks, -f) unlimited
<p>pending signals (-i) 16382
<p>max locked memory (kbytes, -l) 64
<p>max memory size (kbytes, -m) unlimited
<p>open files (-n) 1024
<p>pipe size (512 bytes, -p) 8
<p>POSIX message queues (bytes, -q) 819200
<p>real-time priority (-r) 0
<p>stack size (kbytes, -s) 8192
<p>cpu time (seconds, -t) unlimited
<p>max user processes (-u) unlimited
<p>virtual memory (kbytes, -v) unlimited
<p>file locks (-x) unlimited
<p>通过ulimit –s可以修改进程栈的大小使这个程序运行OK（也可能不行，跟硬件有关）。
<p>我们这里数组大小不止用到了8192k，因为linux下还有一个栈的缓冲区。
<p>实际上进程在运行时并不一定会用到8192k大小的栈，这是一个最大值，可以写两个使用不同栈大小的例子，pause后，查看/proc/*/maps试验下。
<p>但线程是不同的，线程的栈可以通过暴露栈指针的方式共享。无论线程使用多小的栈，进程都会分配一定数目（我的是8M，可以通过线程属性函数来查看）大小的栈给线程使用。如果线程不是以detach结束的，那么只有用join函数获得线程退出状态后才能回收该线程资源，这就是最开始我们说到join函数的作用。
<p>用一个例子测试下线程数目：</p>
<div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #cc6633">#include</span> &lt;stdio.h&gt;<br><br><span style="color: #cc6633">#include</span> &lt;string.h&gt;<br><br><span style="color: #cc6633">#include</span> &lt;pthread.h&gt;<br><br><span style="color: #0000ff">void</span> *test(<span style="color: #0000ff">void</span> *arg)<br><br>{<br><br><span style="color: #008000">/*pthread_detach(pthread_self());*/</span><br><br>}<br><br><span style="color: #0000ff">int</span> main()<br><br>{<br><br><span style="color: #0000ff">int</span> err;<br><br><span style="color: #0000ff">int</span> i = 0;<br><br>pthread_t tid;<br><br>pthread_attr_t attr;<br><br>pthread_attr_init(&amp;attr);<br><br>pthread_attr_setstacksize(&amp;attr,1024*1024*16);<br><br><span style="color: #0000ff">while</span> (1) {<br><br>err = pthread_create(&amp;tid,NULL,test,NULL);<br><br><span style="color: #008000">/*err = pthread_create(&amp;tid,&amp;attr,test,NULL);*/</span><br><br><span style="color: #0000ff">if</span> (err!=0) {<br><br>printf(<span style="color: #006080">"create thread error: %s!\n"</span>,strerror(err));<br><br>exit(1);<br><br>}<br><br>++i;<br><br>printf(<span style="color: #006080">"i=%d\n"</span>,i);<br><br>}<br><br><span style="color: #0000ff">return</span> 0;<br><br>}<br><br></pre><br></div>
<p>我的机器上结果是381，有时382，注意此时这里返回值就是最开始提到的EAGAIN。如果注释放开的话，就可以一直运行下去，因为资源被回收。不过用有的机器试验时，数量虽然增大了，但并不能一直运行下去。没想清楚什么原因。
<p>程序里有几个关于属性的函数，不过暂时没有用到，关于函数的作用，在pthread.h里可以直接看到。
<p>从网上搜到的关于线程最大数目的解释：
<p>这个值和理论完全相符，因为 32 位 linux 下的进程用户空间是 3G 的大小，也就是 3072M，用 3072M 除以 8M 得 384，但是实际上代码段和数据段等还要占用一些空间，这个值应该向下取整到 383，再减去主线程，得到 382。
<p>那为什么 linuxthreads 上还要少一个线程呢？这可太对了，因为 linuxthreads 还需要一个管理线程
<p>为了突破内存的限制，可以有两种方法
<p>1) 用 ulimit -s 1024 减小默认的栈大小
<p>2) 调用 pthread_create 的时候用 pthread_attr_getstacksize 设置一个较小的栈大小
<p>要注意的是，即使这样的也无法突破 1024 个线程的硬限制，除非重新编译 C 库。
<p>虽然结果不是确定的，不过这个解释感觉也还是很合理的。
<p>可以通过程序里线程的attr（即在create的时候不采用NULL而采用这个attr）建立线程观察下线程最大数目再计算下验证下结果。
<p>关于最开始那个程序的段错误，在线程里一样会有，相应的通过pthread_attr_setstacksize(&amp;attr,stackSize)就可以解决了。
<p>关于属性，很多一知半解的，就不拿上来贻笑大方了。
<p>关于pthread多线程编程，用的多的话，其实需要学习的地方还有很多，感觉这些能够满足一些基本的使用了，其他的比如信号量等，等再有使用上的心得的时候再上来总结了。
<img src ="http://www.cppblog.com/izualzhy/aggbug/160123.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/izualzhy/" target="_blank">izualzhy</a> 2011-11-14 22:47 <a href="http://www.cppblog.com/izualzhy/archive/2011/11/14/160123.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>pthread多线程学习笔记五条件变量4使用之signal只能唤醒当前处于wait的线程</title><link>http://www.cppblog.com/izualzhy/archive/2011/11/14/160122.html</link><dc:creator>izualzhy</dc:creator><author>izualzhy</author><pubDate>Mon, 14 Nov 2011 14:45:00 GMT</pubDate><guid>http://www.cppblog.com/izualzhy/archive/2011/11/14/160122.html</guid><wfw:comment>http://www.cppblog.com/izualzhy/comments/160122.html</wfw:comment><comments>http://www.cppblog.com/izualzhy/archive/2011/11/14/160122.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/izualzhy/comments/commentRss/160122.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/izualzhy/services/trackbacks/160122.html</trackback:ping><description><![CDATA[<p>pthread多线程学习笔记五条件变量4使用之signal只能唤醒当前处于wait的线程 <p><strong>直奔主题，如果signal的时候没有线程在条件等待队列里，那么本次signal就没有效果，后续的线程进入条件队列之后，无法被之前的signal唤醒。</strong> <p>似乎这与Windows上不一样？ <p>考虑一个情形，旅客在出租车点排队（进入wait队列），当有出租车到来时，鸣笛或者干啥的（总之就是signal），旅客上车。 <p>于是有了下面这个例子：</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #cc6633">#include</span> &lt;stdio.h&gt;<br><br><span style="color: #cc6633">#include</span> &lt;pthread.h&gt;<br><br>pthread_cond_t taxiCond;<br><br>pthread_mutex_t taxiMutex;<br><br><span style="color: #0000ff">void</span> *travelerArrive(<span style="color: #0000ff">void</span> *name)<br><br>{<br><br>printf(<span style="color: #006080">"Traveler: %s need a taxi now!\n"</span>,(<span style="color: #0000ff">char</span>*)name);<br><br>pthread_mutex_lock(&amp;taxiMutex);<br><br>pthread_cond_wait(&amp;taxiCond, &amp;taxiMutex);<br><br>pthread_mutex_unlock(&amp;taxiMutex);<br><br>printf(<span style="color: #006080">"Traveler: %s now got a taxi!\n"</span>,(<span style="color: #0000ff">char</span>*)name);<br><br>pthread_exit((<span style="color: #0000ff">void</span>*)0);<br><br>}<br><br><span style="color: #0000ff">void</span> *taxiArrive(<span style="color: #0000ff">void</span> *name)<br><br>{<br><br>printf(<span style="color: #006080">"Taxi %s arrives\n"</span>,(<span style="color: #0000ff">char</span>*)name);<br><br>pthread_cond_signal(&amp;taxiCond);<br><br>pthread_exit((<span style="color: #0000ff">void</span>*)0);<br><br>}<br><br><span style="color: #0000ff">int</span> main()<br><br>{<br><br>pthread_t thread;<br><br>pthread_attr_t threadAttr;<br><br>pthread_attr_init(&amp;threadAttr);<br><br>pthread_cond_init(&amp;taxiCond,NULL);<br><br><span style="color: #008000">/*pthread_create(&amp;thread, &amp;threadAttr, travelerArrive, (void*)("Liona"));*/</span><br><br><span style="color: #008000">/*sleep(1);*/</span><br><br>pthread_create(&amp;thread, &amp;threadAttr, taxiArrive, (<span style="color: #0000ff">void</span>*)(<span style="color: #006080">"Jack"</span>));<br><br>sleep(1);<br><br>pthread_create(&amp;thread, &amp;threadAttr, travelerArrive, (<span style="color: #0000ff">void</span>*)(<span style="color: #006080">"Susan"</span>));<br><br>sleep(1);<br><br>pthread_create(&amp;thread, &amp;threadAttr, taxiArrive, (<span style="color: #0000ff">void</span>*)(<span style="color: #006080">"Mike"</span>));<br><br>sleep(1);<br><br><span style="color: #0000ff">return</span> 0;<br><br>}<br></pre><br></div>
<p>当Jack出租车到达后，signal，实际上没有效果。
<p>当Susan到了后，进入wait队列，是收不到哦啊Jack的signal的。
<p>只有当Mike出租车到了后，signal，Susan收到。
<p>程序输出：
<p>Taxi Jack arrives
<p>Traveler: Susan need a taxi now!
<p>Taxi Mike arrives
<p>Traveler: Susan now got a taxi!
<p>如果觉得这样不合理，其实容易改变，加一个关于旅客人数的全局变量即可，修改后的程序如下：</p>
<div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #cc6633">#include</span> &lt;stdio.h&gt;<br><br><span style="color: #cc6633">#include</span> &lt;pthread.h&gt;<br><br>pthread_cond_t taxiCond;<br><br>pthread_mutex_t taxiMutex;<br><br><span style="color: #0000ff">int</span> travelerCount = 0;<br><br><span style="color: #0000ff">void</span> *travelerArrive(<span style="color: #0000ff">void</span> *name)<br><br>{<br><br>printf(<span style="color: #006080">"Traveler: %s need a taxi now!\n"</span>,(<span style="color: #0000ff">char</span>*)name);<br><br>pthread_mutex_lock(&amp;taxiMutex);<br><br>travelerCount++;<br><br>pthread_cond_wait(&amp;taxiCond, &amp;taxiMutex);<br><br>travelerCount--;<br><br>pthread_mutex_unlock(&amp;taxiMutex);<br><br>printf(<span style="color: #006080">"Traveler: %s now got a taxi!\n"</span>,(<span style="color: #0000ff">char</span>*)name);<br><br>pthread_exit((<span style="color: #0000ff">void</span>*)0);<br><br>}<br><br><span style="color: #0000ff">void</span> *taxiArrive(<span style="color: #0000ff">void</span> *name)<br><br>{<br><br>printf(<span style="color: #006080">"Taxi %s arrives\n"</span>,(<span style="color: #0000ff">char</span>*)name);<br><br><span style="color: #0000ff">while</span> (1) {<br><br>pthread_mutex_lock(&amp;taxiMutex);<br><br><span style="color: #0000ff">if</span> (travelerCount&gt;0) {<br><br>pthread_cond_signal(&amp;taxiCond);<br><br>pthread_mutex_unlock(&amp;taxiMutex);<br><br><span style="color: #0000ff">break</span>;<br><br>}<br><br>pthread_mutex_unlock(&amp;taxiMutex);<br><br>}<br><br>pthread_exit((<span style="color: #0000ff">void</span>*)0);<br><br>}<br><br><span style="color: #0000ff">int</span> main()<br><br>{<br><br>pthread_t thread;<br><br>pthread_attr_t threadAttr;<br><br>pthread_attr_init(&amp;threadAttr);<br><br>pthread_cond_init(&amp;taxiCond,NULL);<br><br><span style="color: #008000">/*pthread_create(&amp;thread, &amp;threadAttr, travelerArrive, (void*)("Liona"));*/</span><br><br><span style="color: #008000">/*sleep(1);*/</span><br><br>pthread_create(&amp;thread, &amp;threadAttr, taxiArrive, (<span style="color: #0000ff">void</span>*)(<span style="color: #006080">"Jack"</span>));<br><br>sleep(1);<br><br>pthread_create(&amp;thread, &amp;threadAttr, taxiArrive, (<span style="color: #0000ff">void</span>*)(<span style="color: #006080">"Join"</span>));<br><br>sleep(1);<br><br>pthread_create(&amp;thread, &amp;threadAttr, travelerArrive, (<span style="color: #0000ff">void</span>*)(<span style="color: #006080">"Susan"</span>));<br><br>sleep(1);<br><br>pthread_create(&amp;thread, &amp;threadAttr, taxiArrive, (<span style="color: #0000ff">void</span>*)(<span style="color: #006080">"Mike"</span>));<br><br>sleep(1);<br><br>pthread_create(&amp;thread, &amp;threadAttr, travelerArrive, (<span style="color: #0000ff">void</span>*)(<span style="color: #006080">"Lyn"</span>));<br><br>sleep(1);<br><br><span style="color: #0000ff">return</span> 0;<br><br>}<br></pre><br></div><img src ="http://www.cppblog.com/izualzhy/aggbug/160122.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/izualzhy/" target="_blank">izualzhy</a> 2011-11-14 22:45 <a href="http://www.cppblog.com/izualzhy/archive/2011/11/14/160122.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>pthread多线程学习笔记五条件变量3使用之当wait遇到pthread_cancel</title><link>http://www.cppblog.com/izualzhy/archive/2011/11/14/160121.html</link><dc:creator>izualzhy</dc:creator><author>izualzhy</author><pubDate>Mon, 14 Nov 2011 14:44:00 GMT</pubDate><guid>http://www.cppblog.com/izualzhy/archive/2011/11/14/160121.html</guid><wfw:comment>http://www.cppblog.com/izualzhy/comments/160121.html</wfw:comment><comments>http://www.cppblog.com/izualzhy/archive/2011/11/14/160121.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/izualzhy/comments/commentRss/160121.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/izualzhy/services/trackbacks/160121.html</trackback:ping><description><![CDATA[<p>pthread多线程学习笔记五条件变量3使用之当wait遇到pthread_cancel <p><strong>pthread_cond_wait,pthread_cond_timewait是被实现为取消点的，取消点的含义是如果该线程是可取消的，那么当到达取消点的时候，该线程会取消掉并返回。</strong> <p>先看一个例子：</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #cc6633">#include</span> &lt;stdio.h&gt;<br><br><span style="color: #cc6633">#include</span> &lt;pthread.h&gt;<br><br><span style="color: #cc6633">#include</span> &lt;unistd.h&gt;<br><br>pthread_mutex_t mutex;<br><br>pthread_cond_t cond;<br><br><span style="color: #0000ff">void</span> *child1(<span style="color: #0000ff">void</span> *arg)<br><br>{<br><br><span style="color: #008000">/*pthread_cleanup_push(pthread_mutex_unlock, &amp;mutex);*/</span><br><br><span style="color: #0000ff">while</span> (1) {<br><br>printf(<span style="color: #006080">"thread 1 get running\n"</span>);<br><br>printf(<span style="color: #006080">"thread 1 pthread_mutex_lock returns %d\n"</span>,pthread_mutex_lock(&amp;mutex));<br><br>pthread_cond_wait(&amp;cond,&amp;mutex);<br><br>printf(<span style="color: #006080">"thread 1 conditional applied\n"</span>);<br><br>pthread_mutex_unlock(&amp;mutex);<br><br>sleep(5);<br><br>}<br><br><span style="color: #008000">/*pthread_cleanup_pop(0);//comment 2*/</span><br><br>}<br><br><span style="color: #0000ff">void</span> *child2(<span style="color: #0000ff">void</span> *arg)<br><br>{<br><br><span style="color: #0000ff">while</span> (1) {<br><br>sleep(3); <span style="color: #008000">//comment 3</span><br><br>printf(<span style="color: #006080">"thread 2 get running.\n"</span>);<br><br>printf(<span style="color: #006080">"thread 2 pthread_mutex_lock returns %d\n"</span>,pthread_mutex_lock(&amp;mutex));<br><br>pthread_cond_wait(&amp;cond,&amp;mutex);<br><br>printf(<span style="color: #006080">"thread 2 conditional applied\n"</span>);<br><br>pthread_mutex_unlock(&amp;mutex);<br><br>sleep(1);<br><br>}<br><br>}<br><br><span style="color: #0000ff">int</span> main(<span style="color: #0000ff">void</span>)<br><br>{<br><br><span style="color: #0000ff">int</span> tid1,tid2;<br><br>printf(<span style="color: #006080">"conditional variable test\n"</span>);<br><br>pthread_mutex_init(&amp;mutex,NULL);<br><br>pthread_cond_init(&amp;cond,NULL);<br><br>pthread_create(&amp;tid1, NULL, child1, NULL);<br><br>pthread_create(&amp;tid2, NULL, child2, NULL);<br><br><span style="color: #0000ff">do</span> {<br><br>sleep(2);<span style="color: #008000">//comment 4</span><br><br>pthread_cancel(tid1);<span style="color: #008000">//comment 5</span><br><br>sleep(2);<span style="color: #008000">//comment 6</span><br><br>pthread_cond_signal(&amp;cond);<br><br>}<span style="color: #0000ff">while</span>(1);<br><br>sleep(100);<br><br>pthread_exit(0);<br><br>}<br></pre><br></div>
<p>如果注释掉的部分不放开的话，线程2会一直停在那里，即使主线程不断的去signal。
<p>原因是：
<p>ß pthread_cond_wait ()和pthread_cond_timedwait()都被实现为取消点，因此，在该处等待的线程将立即重新运行，在重新锁定mutex后离开 pthread_cond_wait()，然后执行取消动作。也就是说如果pthread_cond_wait()被取消，mutex是保持锁定状态的，因而需要定义退出回调函数来为其解锁。
<p>好了，其实要说明的就是上面这句话。
<img src ="http://www.cppblog.com/izualzhy/aggbug/160121.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/izualzhy/" target="_blank">izualzhy</a> 2011-11-14 22:44 <a href="http://www.cppblog.com/izualzhy/archive/2011/11/14/160121.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>pthread多线程学习笔记五条件变量2使用</title><link>http://www.cppblog.com/izualzhy/archive/2011/11/14/160120.html</link><dc:creator>izualzhy</dc:creator><author>izualzhy</author><pubDate>Mon, 14 Nov 2011 14:41:00 GMT</pubDate><guid>http://www.cppblog.com/izualzhy/archive/2011/11/14/160120.html</guid><wfw:comment>http://www.cppblog.com/izualzhy/comments/160120.html</wfw:comment><comments>http://www.cppblog.com/izualzhy/archive/2011/11/14/160120.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/izualzhy/comments/commentRss/160120.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/izualzhy/services/trackbacks/160120.html</trackback:ping><description><![CDATA[<p>pthread多线程学习笔记五条件变量2使用 <p>上篇笔记的例子运行效果没有问题，但有些疑问还没搞清楚。 <p><strong>wait函数并不是单使该线程进入休眠。</strong> <p>ß wait函数做以下三步的操作： <p>ß 1.释放Mutex 2.阻塞等待（不耗费cpu周期） 3.当被唤醒时，重新锁定互斥锁并重新测试条件是否满足 。 <p>ß 需要重新测试条件的原因是因为可能存在多个consumer的情况，即如果线程不止两个而是多个，即使线程被唤醒了，如果一个consumer取走了列表里的产品，那么另外一个consumer需要重新进入休眠等待。这也是为什么用while不用if去判断的原因。条件变量只是起阻塞和唤醒线程的作用，具体的判断条件还需用户给出。从wait或者timewait调用成功返回时，线程需要重新计算条件，因为其他的线程可能已经在运行并改变了条件。 <p>wait函数会在 休眠等待之前释放锁，因此producer是不用担心一直获取不到锁的。 <p>传递给wait的互斥量对条件进行保护，调用者把锁住的互斥量传给函数。函数把调用线程放到等待条件的线程列表上，然后对互斥量解锁，这两个操作是原子操作。这样就关闭了条件检查和线程进入休眠状态等待条件改变这两个操作之间的时间通道，这样线程就不会错过条件的任何变化。这就是互斥量和条件一起使用的原因，如果consumer判断到列表为空，正准备进入休眠，而此时producer产生节点放到了列表里，consumer却接着进入休眠很明显不是我们想要的，如果producer在其休眠前发出了信号，又会造成没有接受者的情形（一会会讲到这个）。wait返回时，互斥量再次被锁住。 <p>要注意，一定要在改变条件之后再给线程发信号。否则无意义的唤醒休眠线程就违反我们最初引入条件变量的目的了 <p><b>关于signal</b><b>与mutex</b><b>的相对位置</b>，《UNIX高级环境编程》里是说都可以的，只要在cond_signal之后能从列表里取出节点。因为是while循环检查条件，所以不会存在问题：线程醒来，发现队列为空，然后返回继续等待。如果代码不能容忍这种竞争，就需要在向线程发送信号的时候占有互斥量。 <p>关于这个，从网上找了下资料，也是各执一词，主要是跟当前系统环境有关系，因此并无定论。下面的这个感觉是比较合理的： <p>pthread_cond_signal即可以放在pthread_mutex_lock和pthread_mutex_unlock之间，也可以放在 pthread_mutex_lock和pthread_mutex_unlock之后，但是各有有缺点。 <p>之间： <p>pthread_mutex_lock <p>xxxxxxx <p>pthread_cond_signal <p>pthread_mutex_unlock <p>缺点：在某下线程的实现中，会造成等待线程从内核中唤醒（由于cond_signal)然后又回到内核空间（因为cond_wait返回后会有原子加锁的 行为），所以一来一回会有性能的问题。但是在LinuxThreads或者NPTL里面，就不会有这个问题，因为在Linux 线程中，有两个队列，分别是cond_wait队列和mutex_lock队列， cond_signal只是让线程从cond_wait队列移到mutex_lock队列，而不用返回到用户空间，不会有性能的损耗。 <p>所以在Linux中推荐使用这种模式。 <p>之后： <p>pthread_mutex_lock <p>xxxxxxx <p>pthread_mutex_unlock <p>pthread_cond_signal <p>优点：不会出现之前说的那个潜在的性能损耗，因为在signal之前就已经释放锁了 <p>缺点：如果unlock和signal之前，有个低优先级的线程正在mutex上等待的话，那么这个低优先级的线程就会抢占高优先级的线程 （cond_wait的线程)，而这在上面的放中间的模式下是不会出现的。 <p>所以，在Linux下最好pthread_cond_signal放中间，但从编程规则上说，其他两种都可以。 <p>我理解为signal后唤醒的线程会具有较高的加锁优先级，如果有多个线程在等待给该互斥量加锁的话，唤醒线程会获取得到锁，而这在大部分情况下都是我们所希望看到的。当然如文章中所言，可能会有性能的问题。 <p>关于signal与broadcast的区别，找到一个解释很有意思（如果我的确看明白了的话）： <p>FiLH wrote On 03/29/06 08:47,: <p>Hello, <p>I wonder what is the effective usage difference between <p>pthread_cond_signal and pthread_cond_broadcast. <p>I understand that the first awake one waiting thread, and the second <p>all the waiting threads (on that condition), <p>That is the difference. <p>but be seen that the <p>awkaed thread should enter a mutex, it seems to me in the second case <p>that only one thread will run while the other one will go back <p>waiting. But than, I see no big differences, so I must miss something, <p>but.. what ? <p>All the threads wake up, and all try to lock the <p>mutex. Only one at a time can succeed, and the others <p>must wait for a later opportunity. Yes, they "go back <p>waiting" -- but they are not waiting for the condition <p>any more, they are waiting to lock the mutex. <p>The bugler sounds Reveille, all the soldiers in the <p>barracks awaken, and they all rush for the lone shower <p>stall. One soldier gets there first and showers, while <p>the others stand around fidgeting. When the first is <p>done, there's a brief struggle among the others until <p>a second soldier hits the shower, and so on until all <p>the soldiers have made themselves nice and clean and <p>ready to go crawl in the mud all day. The soldiers who <p>don't happen to be first into the shower don't all go <p>back to bed and await another bugle call (they might <p>wish to, but the Drill Sergeant has other ideas). <p>ok。可能关于一些问题，更多的还需要具体情况具体分析。</p><img src ="http://www.cppblog.com/izualzhy/aggbug/160120.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/izualzhy/" target="_blank">izualzhy</a> 2011-11-14 22:41 <a href="http://www.cppblog.com/izualzhy/archive/2011/11/14/160120.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>pthread多线程学习笔记五条件变量1介绍</title><link>http://www.cppblog.com/izualzhy/archive/2011/11/14/160119.html</link><dc:creator>izualzhy</dc:creator><author>izualzhy</author><pubDate>Mon, 14 Nov 2011 14:40:00 GMT</pubDate><guid>http://www.cppblog.com/izualzhy/archive/2011/11/14/160119.html</guid><wfw:comment>http://www.cppblog.com/izualzhy/comments/160119.html</wfw:comment><comments>http://www.cppblog.com/izualzhy/archive/2011/11/14/160119.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/izualzhy/comments/commentRss/160119.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/izualzhy/services/trackbacks/160119.html</trackback:ping><description><![CDATA[<p>pthread多线程学习笔记五条件变量1介绍 <p>互斥量是用来上锁的。有时候我们需要这样一种情形： <p>线程A需要等某个条件成立才能继续往下执行，现在这个条件不成立，线程A就阻塞等待，而线程B在执行过程中使这个条件成立了，就唤醒A继续执行。 <p>使用互斥量固然可以，线程A不断的去尝试加锁，但却造成cpu周期的浪费，线程A的阻塞等待能是不耗费cpu周期的？ <p>这就是引入条件变量的作用。 <p>ß 条件变量是用来等待而不是用来上锁的。条件变量用来自动阻塞一个线程，直到某特殊情况发生为止。通常条件变量和互斥锁同时使用。 <p>ß 条件变量使我们可以睡眠等待某种条件出现。条件变量是利用线程间共享的全局变量进行同步的一种机制，主要包括两个动作：一个线程等待"条件变量的条件成立"而挂起；另一个线程使"条件成立"（给出条件成立信号）。 <p>针对条件变量的这两个动作，就定义了条件变量响应的两个函数。 <p>等待： <p>ß int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); <p>ß int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex_t *mutex, const struct timespec *timeout) <p>第二个函数仅比第一个多了时间变量，如果给定时间内还未被唤醒，则返回ETIMEDOUT。注意时间是一个绝对值而不是一个相对值，具体使用可以先使用gettimeofday函数获得时间。 <p>唤醒： <p>ß int pthread_cond_signal(pthread_cond_t *cond) <p>ß int pthread_cond_broadcast(pthread_cond_t *cond) <p>POSIX为了简化实现，允许pthread_cond_signal在实现的时候可以唤醒不止一个线程 <p>条件变量的类型标识符是pthread_cond_t,与互斥量一样，需要初始化，用完后需要销毁。 <p>ß 初始化: <p>int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t*attr); <p>PTHREAD_COND_INITIALIZER <p>ß 销毁：int pthread_cond_destroy(pthread_cond_t *cond) <p>看一个例子，有点长，是生产者-消费者模型的例子。从一篇教程里找到的，尽量的完善了下，修改了其中可能引起问题的地方。 <p>生产者和消费者都是单独的一个线程，生产者生产产品，消费者从中取出产品，产品是一个队列，生产者new一个节点添加进来，消费者取出一个节点并free掉，当消费者取的速度很快，而生产者生产的很慢时，消费者就进入休眠等等（wait），而当生产者生产产品后，就唤醒（signal）消费者队列。程序节点定义为一个结构体msg。</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #cc6633">#include</span> &lt;stdlib.h&gt;<br><br><span style="color: #cc6633">#include</span> &lt;pthread.h&gt;<br><br><span style="color: #cc6633">#include</span> &lt;stdio.h&gt;<br><br><span style="color: #0000ff">struct</span> msg {<br><br><span style="color: #0000ff">struct</span> msg *next;<br><br><span style="color: #0000ff">int</span> num;<br><br>};<br><br><span style="color: #0000ff">volatile</span> <span style="color: #0000ff">struct</span> msg *head;<br><br>pthread_cond_t hasProduct = PTHREAD_COND_INITIALIZER;<br><br>pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;<br><br><span style="color: #0000ff">void</span> *consumer(<span style="color: #0000ff">void</span> *p)<br><br>{<br><br><span style="color: #0000ff">struct</span> msg *mp;<br><br><span style="color: #0000ff">for</span>(;;) {<br><br>pthread_mutex_lock(&amp;lock);<br><br><span style="color: #0000ff">while</span> (head==NULL) {<br><br><span style="color: #008000">/*if (head==NULL) {*/</span><br><br><span style="color: #008000">//条件受互斥锁保护?</span><br><br><span style="color: #008000">//用while不用if?</span><br><br>printf(<span style="color: #006080">"consumer entering wait......\n"</span>);<br><br>pthread_cond_wait(&amp;hasProduct,&amp;lock);<br><br>printf(<span style="color: #006080">"consumer leaveing wait : %d......\n"</span>,head-&gt;num);<br><br>}<br><br>mp = head;<br><br>head = mp-&gt;next;<br><br>printf(<span style="color: #006080">"Consume %d\n"</span>,mp-&gt;num);<br><br>pthread_mutex_unlock(&amp;lock);<br><br>free(mp);<br><br>sleep(rand()%5);<br><br>}<br><br>}<br><br><span style="color: #0000ff">void</span> *producer(<span style="color: #0000ff">void</span> *p)<br><br>{<br><br><span style="color: #0000ff">struct</span> msg *mp;<br><br><span style="color: #0000ff">for</span>(;;) {<br><br>mp = malloc(<span style="color: #0000ff">sizeof</span>(<span style="color: #0000ff">struct</span> msg));<br><br>mp-&gt;num = rand()%1000 + 1;<br><br>pthread_mutex_lock(&amp;lock);<br><br>mp-&gt;next = head;<br><br>head = mp;<br><br>printf(<span style="color: #006080">"Produce %d\n"</span>,mp-&gt;num);<br><br>pthread_mutex_unlock(&amp;lock);<br><br>pthread_cond_signal(&amp;hasProduct);<br><br><span style="color: #008000">//signal与lock位置无关</span><br><br>sleep(rand()%5);<br><br>}<br><br>}<br><br><span style="color: #0000ff">int</span> main(<span style="color: #0000ff">int</span> argc, <span style="color: #0000ff">char</span> *argv[])<br><br>{<br><br>pthread_t pid,cid;<br><br>srand(time(NULL));<br><br>pthread_create(&amp;pid,NULL, producer, NULL);<br><br>pthread_create(&amp;cid,NULL, consumer, NULL);<br><br>pthread_join(pid,NULL);<br><br>pthread_join(cid,NULL);<br><br><span style="color: #0000ff">struct</span> msg* mp = head;<br><br><span style="color: #0000ff">while</span> (head!=NULL) {<br><br>mp = head;<br><br>head = head-&gt;next;<br><br>printf(<span style="color: #006080">"main thread: %d\n"</span>,mp-&gt;num);<br><br>free(mp);<br><br>}<br><br><span style="color: #0000ff">return</span> 0;<br><br>}<br></pre><br></div>
<p>这个例子是多线程编程里比较经典的例子，刚开始学习条件变量时其实很多问题没弄明白。没关系，其实很多条件变量的例子形式都差不多是这个样子。关于我的疑问，先提出来，下篇笔记里一个一个记录下找到的和想到的答案。。。
<p><strong>1. consumer里为什么是while而不是if，要知道producer是改变了条件了才signal的。</strong>
<p><strong>2. wait一定要在lock之后，为什么用mutex去保护cond?</strong>
<p><strong>3. signal的位置和mutex有关么?</strong>
<p><strong>4. wait函数做了什么，如果只是休眠等待的话。producer会阻塞在lock函数上（consumer先lock了mutex）。</strong><img src ="http://www.cppblog.com/izualzhy/aggbug/160119.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/izualzhy/" target="_blank">izualzhy</a> 2011-11-14 22:40 <a href="http://www.cppblog.com/izualzhy/archive/2011/11/14/160119.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>pthread多线程学习笔记四互斥量2使用</title><link>http://www.cppblog.com/izualzhy/archive/2011/11/13/160047.html</link><dc:creator>izualzhy</dc:creator><author>izualzhy</author><pubDate>Sun, 13 Nov 2011 14:58:00 GMT</pubDate><guid>http://www.cppblog.com/izualzhy/archive/2011/11/13/160047.html</guid><wfw:comment>http://www.cppblog.com/izualzhy/comments/160047.html</wfw:comment><comments>http://www.cppblog.com/izualzhy/archive/2011/11/13/160047.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/izualzhy/comments/commentRss/160047.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/izualzhy/services/trackbacks/160047.html</trackback:ping><description><![CDATA[<p>pthread多线程学习笔记四互斥量2使用 <p>上篇笔记介绍了互斥量的基本定义，这篇主要介绍其使用方法。 <p>对应其作用，关于互斥量的函数有这么几个： <p>1. 初始化：int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);或者Pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//静态分配 <p>2. 加锁：Int pthread_mutex_lock(pthread_mutex_t* mutex); Int pthread_mutex_trylock(pthread_mutex_t* mutex); <p>3. 解锁Int pthread_mutex_unlock(pthread_mutex_t* mutex) <p>4. 销毁：Int pthread_mutex_destroy(pthread_mutex_t *mutex); <p>具体的使用直接看个例子，从《UNIX 环境高级编程》上抄的：</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #008000">/*mutex.c*/</span><br><br><span style="color: #cc6633">#include</span> &lt;stdio.h&gt;<br><br><span style="color: #cc6633">#include</span> &lt;stdlib.h&gt;<br><br><span style="color: #cc6633">#include</span> &lt;unistd.h&gt;<br><br><span style="color: #cc6633">#include</span> &lt;pthread.h&gt;<br><br><span style="color: #cc6633">#include</span> &lt;errno.h&gt;<br><br>pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;<br><br><span style="color: #0000ff">int</span> lock_var;<br><br>time_t end_time;<br><br><span style="color: #0000ff">void</span> pthread1(<span style="color: #0000ff">void</span> *arg);<br><br><span style="color: #0000ff">void</span> pthread2(<span style="color: #0000ff">void</span> *arg);<br><br><span style="color: #0000ff">int</span> main(<span style="color: #0000ff">int</span> argc, <span style="color: #0000ff">char</span> *argv[])<br><br>{<br><br>pthread_t id1,id2;<br><br>pthread_t mon_th_id;<br><br><span style="color: #0000ff">int</span> ret;<br><br>end_time = time(NULL) + 10;<br><br><span style="color: #008000">/** 互斥锁初始化*/</span><br><br>pthread_mutex_init(&amp;mutex,NULL);<br><br><span style="color: #008000">/** 创建两个线程*/</span><br><br>ret = pthread_create(&amp;id1,NULL,(<span style="color: #0000ff">void</span> *)pthread1,NULL);<br><br><span style="color: #0000ff">if</span> (ret!=0) {<br><br>perror(<span style="color: #006080">"pthread create error.\n"</span>);<br><br>exit(-1);<br><br>}<br><br>ret = pthread_create(&amp;id2,NULL,(<span style="color: #0000ff">void</span> *)pthread2,NULL);<br><br><span style="color: #0000ff">if</span> (ret!=0) {<br><br>perror(<span style="color: #006080">"pthread create error.\n"</span>);<br><br>}<br><br>pthread_join(id1,NULL);<br><br>pthread_join(id2,NULL);<br><br>pthread_mutex_destroy(&amp;mutex);<br><br>exit(0);<br><br>}<br><br><span style="color: #0000ff">void</span> pthread1(<span style="color: #0000ff">void</span> *arg)<br><br>{<br><br><span style="color: #0000ff">int</span> i;<br><br><span style="color: #0000ff">while</span> (time(NULL) &lt; end_time) {<br><br><span style="color: #008000">/** 互斥锁上锁*/</span><br><br><span style="color: #0000ff">if</span> (pthread_mutex_lock(&amp;mutex)!=0) {<br><br>perror(<span style="color: #006080">"pthread_mutex_lock"</span>);<br><br>} <span style="color: #0000ff">else</span> {<br><br>printf(<span style="color: #006080">"pthread1:pthread1 lock the variable %d\n"</span>,lock_var);<br><br>}<br><br><span style="color: #0000ff">for</span> (i=0; i&lt;2; i++) {<br><br>sleep(1);<br><br>lock_var++;<br><br>}<br><br><span style="color: #008000">/** 互斥锁解锁*/</span><br><br><span style="color: #0000ff">if</span> (pthread_mutex_unlock(&amp;mutex)!=0) {<br><br>perror(<span style="color: #006080">"pthread_mutex_unlock."</span>);<br><br>} <span style="color: #0000ff">else</span> {<br><br>printf(<span style="color: #006080">"pthread1:pthread1 unlock the variable %d\n"</span>,lock_var);<br><br>}<br><br>sleep(1);<br><br>}<br><br>}<br><br><span style="color: #0000ff">void</span> pthread2(<span style="color: #0000ff">void</span> *arg)<br><br>{<br><br><span style="color: #0000ff">int</span> ret;<br><br><span style="color: #0000ff">while</span> (time(NULL) &lt; end_time) {<br><br><span style="color: #008000">/** 测试互斥锁*/</span><br><br>ret = pthread_mutex_trylock(&amp;mutex);<br><br><span style="color: #0000ff">if</span> (ret == EBUSY) {<br><br>printf(<span style="color: #006080">"pthread2:the variable is locked by pthread1\n"</span>);<br><br>} <span style="color: #0000ff">else</span> {<br><br><span style="color: #0000ff">if</span> (ret!=0) {<br><br>perror(<span style="color: #006080">"pthread_mutex_trylock"</span>);<br><br>exit(1);<br><br>} <span style="color: #0000ff">else</span> {<br><br>printf(<span style="color: #006080">"pthread2:pthread2 got lock. The variable is %d\n"</span>,lock_var);<br><br>}<br><br><span style="color: #0000ff">if</span> (pthread_mutex_unlock(&amp;mutex)!=0) {<br><br>perror(<span style="color: #006080">"pthread_mutex_unlock"</span>);<br><br>} <span style="color: #0000ff">else</span> {<br><br>printf(<span style="color: #006080">"pthread2:pthread2 unlock the variable\n"</span>);<br><br>}<br><br>}<br><br>sleep(3);<br><br>}<br><br>}<br><br></pre><br></div>
<p>需要说明的有两点：
<p>1. lock函数会阻塞等待，直到获得锁
<p>2. trylock函数不会阻塞等待，如果互斥量当前被锁，则返回EBUSY值。
<p>容易出错的情形：
<p>A
<p>ß pthread_mutex_lock (theMutex);
<p>ß pthread_mutex_lock (theMutex);
<p>ß pthread_mutex_unlock (theMutex);
<p>ß pthread_mutex_unlock (theMutex); 
<p>表面上看程序加锁两次，然后解锁两次没有错，实际上加锁第二次的时候就出错了。
<p>B．
<p><a href="http://www.cppblog.com/images/cppblog_com/izualzhy/WindowsLiveWriter/pthread2_142F3/clip_image002_2.gif"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="clip_image002" border="0" alt="clip_image002" src="http://www.cppblog.com/images/cppblog_com/izualzhy/WindowsLiveWriter/pthread2_142F3/clip_image002_thumb.gif" width="210" height="240"></a><a href="http://www.cppblog.com/images/cppblog_com/izualzhy/WindowsLiveWriter/pthread2_142F3/clip_image004_2.gif"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="clip_image004" border="0" alt="clip_image004" src="http://www.cppblog.com/images/cppblog_com/izualzhy/WindowsLiveWriter/pthread2_142F3/clip_image004_thumb.gif" width="210" height="240"></a>
<p>即存在多个互斥量时的问题，两个线程都在等在另一个线程解锁才能继续往下执行。
<p>碰到这种情况，我们一般约定一个1-2-3…的加锁顺序，所有线程都遵守这一约定才行。
<p>但即使这样，有时候应用程序的结构使得对互斥量加锁进行排序是很困难的，如果涉及了太多的锁和数据结构，可用的函数并不能把它转换成简单的层次，那么就需要采用另外的办法。可以先释放所有的锁，然后过一段时间再试。这种情况可以使用pthread_mutex_trylock接口避免死锁。
<p>ß 互斥锁一个明显的缺点是它只有两种状态：锁定和非锁定。设想一种简单情景：多个线程访问同一个共享资源时，并不知道何时应该使用共享资源，如果在临界区里加入判断语句，或者可以有效，但一来效率不高，二来复杂环境下就难以编写了，这是我们需要一个结构，能在条件成立时触发相应线程，进行变量修改和访问。
<p>针对此问题，下一篇开始学习条件变量。
<img src ="http://www.cppblog.com/izualzhy/aggbug/160047.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/izualzhy/" target="_blank">izualzhy</a> 2011-11-13 22:58 <a href="http://www.cppblog.com/izualzhy/archive/2011/11/13/160047.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>pthread多线程学习笔记四互斥量1介绍</title><link>http://www.cppblog.com/izualzhy/archive/2011/11/13/160046.html</link><dc:creator>izualzhy</dc:creator><author>izualzhy</author><pubDate>Sun, 13 Nov 2011 14:56:00 GMT</pubDate><guid>http://www.cppblog.com/izualzhy/archive/2011/11/13/160046.html</guid><wfw:comment>http://www.cppblog.com/izualzhy/comments/160046.html</wfw:comment><comments>http://www.cppblog.com/izualzhy/archive/2011/11/13/160046.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/izualzhy/comments/commentRss/160046.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/izualzhy/services/trackbacks/160046.html</trackback:ping><description><![CDATA[<p>pthread多线程学习笔记四互斥量1介绍 <p>多线程资源共享可以说有利有弊，这点从笔记一可以清楚的看到（子线程修改内存后，主线程可以看到，但子线程free后，主线程再次free就有问题了）。 <p>更直接一点的错误，如果子线程修改那块内存的时候，主线程同时在修改会发生什么状况。答案是：不确定。因此，线程同步变得很重要。解决方法就是不允许多个线程同时去修改一个变量。 <p>ß 当一个线程修改变量时，其他线程在读取这个变量的值时就可能看到不一样的数值。 <p>ß 在变量修改时间多于一个存储器访问周期的处理器结构中，当存储器读与存储器写这两个周期交叉时，这种潜在的不一致性就会出现。 <p>因此引入了互斥量。 <p>看个例子可能容易理解一些： <p>void *threadA(void *) { i++; } <p>void *threadB(void *) { i++; } <p>对应于自增的操作： <p><a href="http://www.cppblog.com/images/cppblog_com/izualzhy/WindowsLiveWriter/pthread1_142A8/clip_image002_2.gif"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="clip_image002" border="0" alt="clip_image002" src="http://www.cppblog.com/images/cppblog_com/izualzhy/WindowsLiveWriter/pthread1_142A8/clip_image002_thumb.gif" width="132" height="240"></a> <a href="http://www.cppblog.com/images/cppblog_com/izualzhy/WindowsLiveWriter/pthread1_142A8/clip_image004_2.gif"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="clip_image004" border="0" alt="clip_image004" src="http://www.cppblog.com/images/cppblog_com/izualzhy/WindowsLiveWriter/pthread1_142A8/clip_image004_thumb.gif" width="132" height="240"></a> <a href="http://www.cppblog.com/images/cppblog_com/izualzhy/WindowsLiveWriter/pthread1_142A8/clip_image006_2.gif"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="clip_image006" border="0" alt="clip_image006" src="http://www.cppblog.com/images/cppblog_com/izualzhy/WindowsLiveWriter/pthread1_142A8/clip_image006_thumb.gif" width="132" height="240"></a> <p>从左到右依次为A线程，B线程和我们看到的i的值。横向的表示同一时间。我们把这种一个时间点上cpu能完成的动作称为原子操作，那么如果操作不是原子操作时，不一致性就出现了。 <p>合理的办法是当A线程修改i的时候，B线程应当阻塞等待，直到A线程修改完毕，B线程再开始修改。或者A去等待B完成。 <p>就像是锁，A，B去修改i的时候都尝试去锁住i，如果i处于没被锁住（解锁）状态，则可以锁上，若i处于锁住状态，则阻塞等待直到i被别的线程开锁后可以锁住i为止。 <p>我刚开始理解为互斥量就是用来保护一个变量的，后来发现是错误的。 <p>就像如果B尝试去修改i的时候没有先尝试去给互斥量加锁，一样可以修改i，一样会产生问题。。。 <p>因此互斥量加锁，解锁的位置都是由我们自己来确定的。 <p>我的理解是，互斥量可以锁住一块区域，因此抛开变量来解释，最直观的就是，当线程A执行某段代码时，不希望别的线程同时来修改其要读取或者修改的变量（可能有多个），因此对互斥量加锁，直到这段代码结束，再对其解锁。这样就一定管用吗？如果线程B执行的某段代码可能会修改线程A所不希望别的线程所修改的那些变量，而线程B又没有先尝试加锁（看下有没有线程已锁住互斥量，若有，则需要阻塞等待）的话，结果并不确定，互斥量是不会起作用的。因此，这更像是个“君子协定”（从一篇教程里看到的，还挺贴切。。。。。。），如何确保程序正确，在哪个线程哪里加锁与解锁都需要写程序的人来保证。互斥量的作用仅仅是加锁与解锁。 <p>真啰嗦。。。不过我确实看了几个例子后才明白。。。 <p>使用互斥量先看个例子： <p>单实例模式（在看一本设计模式书的时候看到的）</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #cc6633">#include</span> &lt;pthread.h&gt;<br><br><span style="color: #cc6633">#include</span> &lt;stdio.h&gt;<br><br><span style="color: #cc6633">#include</span> &lt;unistd.h&gt;<br><br><span style="color: #0000ff">class</span> Test {<br><br><span style="color: #0000ff">public</span>:<br><br><span style="color: #0000ff">static</span> Test* instance() {<br><br><span style="color: #0000ff">if</span> (NULL == m_instance) {<br><br>sleep(1);<br><br>printf(<span style="color: #006080">"m_instance is NULL\n"</span>);<br><br>m_instance = <span style="color: #0000ff">new</span> Test;<br><br>}<br><br><span style="color: #0000ff">return</span> m_instance;<br><br>}<br><br><span style="color: #0000ff">static</span> Test* m_instance;<br><br><span style="color: #0000ff">void</span> print(<span style="color: #0000ff">char</span>* tip) <br><br>{ <br><br>printf(<span style="color: #006080">"In: %s,Test print %x\n"</span>,tip,m_instance); <br><br>printf(<span style="color: #006080">"tid: %x\n"</span>,pthread_self());<br><br>}<br><br><span style="color: #0000ff">private</span>:<br><br>Test() {}<br><br>Test(<span style="color: #0000ff">const</span> Test&amp; ) {}<br><br>};<br><br>Test* Test::m_instance = NULL;<br><br><span style="color: #0000ff">void</span> *thr_fn(<span style="color: #0000ff">void</span>* arg)<br><br>{<br><br>Test::instance()-&gt;print(<span style="color: #006080">"thread"</span>);<br><br><span style="color: #0000ff">return</span> ((<span style="color: #0000ff">void</span>*)0);<br><br>}<br><br><span style="color: #0000ff">int</span> main()<br><br>{<br><br><span style="color: #0000ff">int</span> err;<br><br>pthread_t tid;<br><br>err = pthread_create(&amp;tid, NULL, thr_fn, NULL);<br><br>Test::instance()-&gt;print(<span style="color: #006080">"main thread1"</span>);<br><br>Test::instance()-&gt;print(<span style="color: #006080">"main thread2"</span>);<br><br>sleep(2);<br><br><span style="color: #0000ff">return</span> 0;<br><br>}<br><br></pre><br></div>
<p>结果会产生两个实例，显然不是我们想要的。
<p>if (NULL == m_instance) {
<p>sleep(1);
<p>printf("m_instance is NULL\n");
<p>这里当发现m_instance为空后，休眠1s，然后new出一个新的出来。
<p>当两个线程运行到这里（sleep(1)是特意加的）。无论哪个线程先调用该函数（主线程开了子线程后，接着调用，两个的时间不会超过1s......）会发现m_instance的确为空，于是休眠1s，然后new一个新的出来。该线程休眠的时候，后调用的线程同样调用到这里，跟之前的一样，发现为空，休眠1s，然后醒来new一个。于是两个线程休眠醒来的时候都会取new一个实例出来。即产生两个单实例的原因。当然可能跟sleep（1）有着关系，但在许多实际项目里，这种情况很明显是要避免的。
<p>产生的原因其实跟之前i++相同，判断的和调用并不是一个原子操作。
<p>如果我们尝试去写下互斥量加锁和解锁两个操作的伪代码：</p>
<div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">lock:<br><br><span style="color: #0000ff">if</span> (mutex &gt; 0) {<span style="color: #008000">//mutex = 1表示空闲</span><br><br>mutex = 0;<br><br><span style="color: #0000ff">return</span> 0;<br><br>} <span style="color: #0000ff">else</span><br><br>挂起等待;<br><br><span style="color: #0000ff">goto</span> lock;<br><br>unlock:<br><br>mutex = 1;<br><br>唤醒等待Mutex的线程;<br><br><span style="color: #0000ff">return</span> 0;<br></pre><br></div>
<p>可以看到跟这个例子一样，if判断和调用并不是一个原子操作。因此互斥量具体实现是这样的：
<p>ß 为了实现互斥锁操作，大多数体系结构都提供了swap或exchange指令，该指令的作用是把寄存器和内存单元的数据相交换，由于只有一条指令，保证了原子性，即使是多处理器平台，访问内存的总线周期也有先后，一个处理器上的交换指令执行时另一个处理器的交换指令只能等待总线周期
<p>实际上上面这句话我几乎没看懂，不过没关系，我想说明的还是那句话，互斥量的作用在这里（使之成为了原子操作），而对变量的保护需要写代码的人（遵循所谓的“君子协议”）来完成。
<img src ="http://www.cppblog.com/izualzhy/aggbug/160046.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/izualzhy/" target="_blank">izualzhy</a> 2011-11-13 22:56 <a href="http://www.cppblog.com/izualzhy/archive/2011/11/13/160046.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>pthread多线程学习笔记三线程清理处理程序</title><link>http://www.cppblog.com/izualzhy/archive/2011/11/13/160045.html</link><dc:creator>izualzhy</dc:creator><author>izualzhy</author><pubDate>Sun, 13 Nov 2011 14:53:00 GMT</pubDate><guid>http://www.cppblog.com/izualzhy/archive/2011/11/13/160045.html</guid><wfw:comment>http://www.cppblog.com/izualzhy/comments/160045.html</wfw:comment><comments>http://www.cppblog.com/izualzhy/archive/2011/11/13/160045.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/izualzhy/comments/commentRss/160045.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/izualzhy/services/trackbacks/160045.html</trackback:ping><description><![CDATA[<p>pthread多线程学习笔记三线程清理处理程序 <p>线程可以安排自己退出时(某些情况下的退出)的回调函数。 <p><font color="#ff0000">Void pthread_cleanup_push(void (*rtn)(void*),void *arg);</font> <p><font color="#ff0000">Void pthread_pop(int execute);</font> <p>这与进程可以用atexit函数安排进程退出时需要调用的函数是类似的。这样的函数称为线程清理处理程序(thread cleanup handler)。 <p>先看下这两个函数的实现：</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #008000">/* Install a cleanup handler: ROUTINE will be called with arguments ARG</span><br><span style="color: #008000"></span><br><span style="color: #008000">when the thread is canceled or calls pthread_exit. ROUTINE will also</span><br><span style="color: #008000"></span><br><span style="color: #008000">be called with arguments ARG when the matching pthread_cleanup_pop</span><br><span style="color: #008000"></span><br><span style="color: #008000">is executed with non-zero EXECUTE argument.</span><br><span style="color: #008000"></span><br><span style="color: #008000">pthread_cleanup_push and pthread_cleanup_pop are macros and must always</span><br><span style="color: #008000"></span><br><span style="color: #008000">be used in matching pairs at the same nesting level of braces. */</span><br><br># define pthread_cleanup_push(routine, arg) \<br><br><span style="color: #0000ff">do</span> { \<br><br>__pthread_cleanup_class __clframe (routine, arg)<br><br><span style="color: #008000">/* Remove a cleanup handler installed by the matching pthread_cleanup_push.</span><br><span style="color: #008000"></span><br><span style="color: #008000">If EXECUTE is non-zero, the handler function is called. */</span><br><br># define pthread_cleanup_pop(execute) \<br><br>__clframe.__setdoit (execute); \<br><br>} <span style="color: #0000ff">while</span> (0)<br></pre><br></div>
<p>我从pthread.h里给照搬过来了，主要是想说明这两个函数实现为宏，要成对使用，英文解释里很明确了呵呵。
<p>注意：
<p>1. 线程可以建立多个清理处理程序，处理程序记录在栈中，也就是说它们的执行顺序与它们的注册顺序相反。
<ol start="2">
<li>当线程执行以下动作时调用</li></ol>
<p>1调用pthread_exit时
<p>2响应取消请求时. 
<p>3用非零execute参数调用pthread_cleanup_pop时。
<p>可以看到return时并不会调用。
<p>3. 如果execute参数置0，清理函数不被调用。无论哪种情况，pthread_cleanup_pop都将删除上次pthread_cleanup_push调用建立的清理处理程序。
<p>直接看个例子,&lt;UNIX 环境高级编程上的&gt;:</p>
<div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #cc6633">#include</span> &lt;stdio.h&gt;<br><br><span style="color: #cc6633">#include</span> &lt;stdlib.h&gt;<br><br><span style="color: #cc6633">#include</span> &lt;pthread.h&gt;<br><br><span style="color: #0000ff">void</span> cleanup(<span style="color: #0000ff">void</span> *arg)<br><br>{<br><br>printf(<span style="color: #006080">"cleanup: %s\n"</span>,(<span style="color: #0000ff">char</span> *)arg);<br><br>}<br><br><span style="color: #0000ff">void</span> *thr_fn1(<span style="color: #0000ff">void</span> *arg)<br><br>{<br><br>printf(<span style="color: #006080">"thread 1 start\n"</span>);<br><br>pthread_cleanup_push(cleanup, <span style="color: #006080">"thread 1 first handler"</span>);<br><br>pthread_cleanup_push(cleanup, <span style="color: #006080">"thread 1 second handler"</span>);<br><br>printf(<span style="color: #006080">"thread 1 push complete\n"</span>);<br><br><span style="color: #0000ff">if</span> (arg)<br><br><span style="color: #0000ff">return</span>((<span style="color: #0000ff">void</span> *)1);<br><br>pthread_cleanup_pop(0);<br><br>pthread_cleanup_pop(0);<br><br><span style="color: #0000ff">return</span>((<span style="color: #0000ff">void</span> *)1);<br><br>}<br><br><span style="color: #0000ff">void</span> *thr_fn2(<span style="color: #0000ff">void</span> *arg)<br><br>{<br><br>printf(<span style="color: #006080">"thread 2 start\n"</span>);<br><br>pthread_cleanup_push(cleanup, <span style="color: #006080">"thread 2 first handler"</span>);<br><br>pthread_cleanup_push(cleanup, <span style="color: #006080">"thread 2 second handler"</span>);<br><br>printf(<span style="color: #006080">"thread 2 push complete\n"</span>);<br><br><span style="color: #0000ff">if</span> (arg)<br><br>pthread_exit((<span style="color: #0000ff">void</span> *)2);<br><br>pthread_cleanup_pop(0);<br><br>pthread_cleanup_pop(0);<br><br>pthread_exit((<span style="color: #0000ff">void</span> *)2);<br><br>}<br><br><span style="color: #0000ff">int</span> main(<span style="color: #0000ff">void</span>)<br><br>{<br><br><span style="color: #0000ff">int</span> err;<br><br>pthread_t tid1,tid2;<br><br><span style="color: #0000ff">void</span> *tret;<br><br>err = pthread_create(&amp;tid1, NULL, thr_fn1, (<span style="color: #0000ff">void</span> *)1);<br><br><span style="color: #0000ff">if</span> (err != 0) {<br><br>printf(<span style="color: #006080">"can't create thread 1: %s\n"</span>,strerror(err));<br><br>exit(-1);<br><br>}<br><br>err = pthread_create(&amp;tid2, NULL, thr_fn2, (<span style="color: #0000ff">void</span> *)1);<br><br><span style="color: #0000ff">if</span> (err != 0) {<br><br>printf(<span style="color: #006080">"can't create thread 2: %s\n"</span>,strerror(err));<br><br>exit(-1);<br><br>}<br><br>err = pthread_join(tid1, &amp;tret);<br><br><span style="color: #0000ff">if</span> (err != 0) {<br><br>printf(<span style="color: #006080">"can't join with thread 1: %s\n"</span>,strerror(err));<br><br>exit(-1);<br><br>}<br><br>printf(<span style="color: #006080">"thread 1 exit code %d\n"</span>,(<span style="color: #0000ff">int</span>)tret);<br><br>err = pthread_join(tid2, &amp;tret);<br><br><span style="color: #0000ff">if</span> (err != 0) {<br><br>printf(<span style="color: #006080">"can't join with thread 2: %s\n"</span>,strerror(err));<br><br>exit(-1);<br><br>}<br><br>printf(<span style="color: #006080">"thread 2 exit code %d\n"</span>,(<span style="color: #0000ff">int</span>)tret);<br><br>}<br><br></pre><br></div>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:0492cea9-f66a-49fe-9f95-3082e3028c47" class="wlWriterEditableSmartContent">Technorati 标签: <a href="http://technorati.com/tags/c%2fc%2b%2b" rel="tag">c/c++</a>,<a href="http://technorati.com/tags/%e5%a4%9a%e7%ba%bf%e7%a8%8b" rel="tag">多线程</a></div>
<p>至此多线程基本的创建，结束，清理的方法就都有了，接下来开始进入互斥量,Mutex,锁（其实是一个东东）…
<img src ="http://www.cppblog.com/izualzhy/aggbug/160045.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/izualzhy/" target="_blank">izualzhy</a> 2011-11-13 22:53 <a href="http://www.cppblog.com/izualzhy/archive/2011/11/13/160045.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>pthread多线程学习笔记二线程终止、取消与获得返回状态</title><link>http://www.cppblog.com/izualzhy/archive/2011/11/13/160024.html</link><dc:creator>izualzhy</dc:creator><author>izualzhy</author><pubDate>Sun, 13 Nov 2011 07:05:00 GMT</pubDate><guid>http://www.cppblog.com/izualzhy/archive/2011/11/13/160024.html</guid><wfw:comment>http://www.cppblog.com/izualzhy/comments/160024.html</wfw:comment><comments>http://www.cppblog.com/izualzhy/archive/2011/11/13/160024.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/izualzhy/comments/commentRss/160024.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/izualzhy/services/trackbacks/160024.html</trackback:ping><description><![CDATA[<p style="margin: 0cm 0cm 0pt"><strong>pthread</strong>多线程学习笔记二线程终止、取消与获得返回状态</p><br /><br /> <p>上篇笔记里可以看到线程函数的开始和结束意味着线程的开始和终止，那么就有一个问题，同其他普通函数一样，如何获得线程返回时的状态？</p> <p>如果子线程运行过程中，主线程需要取消子线程，该如何做？</p> <p>子线程退出方式有哪些？</p><br /> <p>&#223; 如果需要只终止某个线程而不终止整个进程，可以有三种方法：</p> <p>1.从线程函数return。这种方法对主线程不适用，从main函数return相当于调用exit。(如果进程中任一线程调用了exit,_Exit或者_exit,那么整个进程就会终止。)</p> <p>2.一个线程可以调用pthread_cancel终止同一进程中的另一个线程。</p> <p>3.线程可以调用pthread_exit终止自己</p><br /> <p>可以用pthread_join等待线程结束并获得其返回值：</p> <p>&#223; int pthread_join(pthread_t thread, void **rval_ptr)</p> <p>返回值：成功返回0，失败返回错误号(ESRCH,EINVAL等)</p> <p>&#223; 通过pthread_join得到的终止状态是不同的，总结如下：</p> <p>1.如果thread线程通过return返回，rval_ptr所指向的单元里存放的是thread线程函数的返回值。</p> <p>2. 如果thread线程被别的线程调用pthread_cancel异常终止掉，rval_ptr所指向的单元里存放的是常数PTHREAD_CANCELED。</p> <p>3.如果thread线程是自己调用pthread_exit终止的，rval_ptr所指向的单元存放的是传给pthread_exit的参数。</p> <p>&#223; 如果对thread线程的终止状态不感兴趣，可以传NULL给rval_ptr参数。</p> <p>同之前一样，每个函数具体的解释就不记录在这里了，很多教程上有，/usr/include/pthread.h文件里也可以看到简单的注解。</p> <p>注意这个函数和进程里的waitpid很像。</p> <p>调用这个函数其实有两个原因：</p> <p>1. 获得线程返回值，存在第二个参数里（指向指针的指针）。</p> <p>2. 如果不想获得函数退出状态，只是单纯的想等待线程结束，可以传NULL给它。要说明的是，一个线程不能被多个线程等待，否则第一个接收到信号的线程成功返回，其余调用pthread_join的线程则返回错误代码ESRCH。</p> <p>一般情况下，线程终止后，其终止状态一直保留到其它线程调用pthread_join获取它的状态为止。因此用这个函数取等待线程结束是必要的，具体系统回收的是那部分资源线程属性里可以体现的很明显，当然肯定就是线程独有的那部分资源&#8230;&#8230;但是线程也可以被置为detach状态，这样的线程一旦终止就立刻回收它占用的所有资源，而不保留终止状态。不能对一个已经处于detach状态的线程调用pthread_join，这样的调用将返回EINVAL。对一个尚未detach的线程调用pthread_join或pthread_detach都可以把该线程置为detach状态，也就是说，不能对同一线程调用两次pthread_join，或者如果已经对一个线程调用了pthread_detach就不能再调用pthread_join了。有兴趣的同学可以做个试验，看下在对每个线程设置为detach状态前后系统可以开的最大线程数目对比，看下是否线程资源回收是必要的。</p> <p>第二点好像太啰嗦了（学的一知半解。。），不过感觉最主要的是也就是说这里。。。。</p><br /><br /> <p>取消线程：</p> <p>int pthread_cancel(pthread_t tid);</p> <p>&#223; 线程可以通过调用该函数来请求取消同一进程中的其他线程。</p> <p>&#223; 在默认情况下，pthread_cancel函数会使得由tid标识的线程的行为表现为如同调用了参数为PTHREAD_CANCELED的pthread_exit函数，但是线程可以选择忽略取消方式或是控制取消方式。注意pthread_cancel并不等待线程终止，它仅仅提出请求。</p> <p>注意：</p> <p>1. #define PTHREAD_CANCELED ((void *) -1)，因此此时通过join获得返回值其实就是-1.</p> <p>2. 该函数仅仅是提出请求。具体被取消线程的动作跟其线程属性相关。</p> <p>例子：</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #cc6633">#include</span> &lt;pthread.h&gt;<br /><br /><span style="color: #cc6633">#include</span> &lt;stdio.h&gt;<br /><br /><br /><br /><br /><span style="color: #0000ff">void</span> cleanup(<span style="color: #0000ff">void</span> *arg)<br /><br />{<br /><br />printf(<span style="color: #006080">"clean up \n"</span>);<br /><br />}<br /><br /><span style="color: #0000ff">char</span> c = <span style="color: #006080">'a'</span>;<br /><br /><br /><br /><br /><span style="color: #0000ff">void</span> *print(<span style="color: #0000ff">void</span> *arg)<br /><br />{<br /><br /><span style="color: #0000ff">int</span> i;<br /><br />pthread_cleanup_push(cleanup,NULL);<br /><br /><span style="color: #0000ff">for</span> ( i=0; i&lt;10; ++i) {<br /><br />printf(<span style="color: #006080">"%s\n"</span>,(<span style="color: #0000ff">char</span> *)arg);<br /><br />sleep(2);<br /><br />}<br /><br /><br /><br /><br />pthread_exit((<span style="color: #0000ff">void</span> *)c);<br /><br />pthread_cleanup_pop(0);<br /><br /><span style="color: #008000">/*exit(NULL);*/</span><br /><br />}<br /><br /><br /><br /><br /><span style="color: #0000ff">int</span> main()<br /><br />{<br /><br />pthread_t pid;<br /><br />pthread_create(&amp;pid,NULL,print,<span style="color: #006080">"hello world."</span>);<br /><br /><span style="color: #008000">/*pthread_detach(pid);*/</span><br /><br /><span style="color: #0000ff">int</span> i;<br /><br /><span style="color: #0000ff">for</span>( i=0; i&lt;10; i++) {<br /><br />printf(<span style="color: #006080">"I'm main thread\n"</span>);<br /><br />sleep(1);<br /><br />}<br /><br /><span style="color: #0000ff">void</span> *ret;<br /><br /><span style="color: #008000">/*pthread_cancel(pid);*/</span><br /><br /><span style="color: #0000ff">int</span> r = pthread_join(pid,&amp;ret);<br /><br /><span style="color: #0000ff">if</span> (r != 0) {<br /><br />printf(<span style="color: #006080">"join error: %s\n"</span>,strerror(r));<br /><br />}<br /><br /><span style="color: #008000">/*r = pthread_join(pid,&amp;ret);*/</span><br /><br /><span style="color: #008000">/*if (r != 0) {*/</span><br /><br /><span style="color: #008000">/*printf("join error: %s\n",strerror(r));*/</span><br /><br /><span style="color: #008000">/*}*/</span><br /><br />printf(<span style="color: #006080">"%d\n"</span>,(<span style="color: #0000ff">int</span>*)ret);<br /><br /><br /><br /><br /><span style="color: #0000ff">return</span> 0;<br /><br />}<br /><br /></pre></div>
<p>这个例子里注释掉的部分是我用来测试这篇笔记里大部分感觉要注意的地方的</p><img src ="http://www.cppblog.com/izualzhy/aggbug/160024.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/izualzhy/" target="_blank">izualzhy</a> 2011-11-13 15:05 <a href="http://www.cppblog.com/izualzhy/archive/2011/11/13/160024.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>pthread多线程学习笔记一线程创建篇</title><link>http://www.cppblog.com/izualzhy/archive/2011/11/13/160022.html</link><dc:creator>izualzhy</dc:creator><author>izualzhy</author><pubDate>Sun, 13 Nov 2011 06:59:00 GMT</pubDate><guid>http://www.cppblog.com/izualzhy/archive/2011/11/13/160022.html</guid><wfw:comment>http://www.cppblog.com/izualzhy/comments/160022.html</wfw:comment><comments>http://www.cppblog.com/izualzhy/archive/2011/11/13/160022.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/izualzhy/comments/commentRss/160022.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/izualzhy/services/trackbacks/160022.html</trackback:ping><description><![CDATA[<p align="left"><span style="font-family: 'Calibri','sans-serif'; font-size: 1pt; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-bidi-theme-font: minor-bidi; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" lang="EN-US"><w:sdtPr></w:sdtPr><w:Sdt id="89512082" title="文章标题" storeitemid="X_BC6F93BF-22BA-4949-BB97-A5EE037A3898" text="t" docpart="C25491BD112C4FE9897CCA633A925D19" xpath="/ns0:BlogPostInfo/ns0:PostTitle"></span><font face="宋体">&nbsp;</font> </p>
<p style="margin: 0cm 0cm 0pt" class="Publishwithline"><strong><font size="5"><font color="#17365d"><span lang="EN-US">pthread</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: major-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: major-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: major-latin">多线程学习笔记一线程创建篇</span><span lang="EN-US"><w:sdtPr></w:sdtPr></span></font></font></strong></p>
<p align="left"></w:Sdt>&nbsp;</p>
<div style="border-bottom: #4f81bd 1pt solid; border-left: medium none; padding-bottom: 2pt; padding-left: 0cm; padding-right: 0cm; border-top: medium none; border-right: medium none; padding-top: 0cm; mso-border-bottom-themecolor: accent1; mso-element: para-border-div">
<p style="margin: 2pt 0cm 0pt" class="underline"><span lang="EN-US"><o:p><font size="1">&nbsp;</font></o:p></span></p></div>
<p style="margin: 0cm 0cm 6pt" class="PadderBetweenControlandBody"><span lang="EN-US"><o:p><font size="1">&nbsp;</font></o:p></span></p>
<p style="margin: 0cm 0cm 10pt" class="MsoNormal"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">最近在学习</span><span lang="EN-US">Linux</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">多线程编程部分，笔记之一：</span></p>
<p style="margin: 0cm 0cm 10pt" class="MsoNormal"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">线程库函数是由</span><span lang="EN-US">POSIX</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">标准定义的，称为</span><span lang="EN-US">POSIX thread</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">或者</span><span lang="EN-US">pthread</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">。在</span><span lang="EN-US">Linux</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">上线程函数位于</span><span lang="EN-US">libpthread</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">共享库中，因此在编译时要加上</span><span lang="EN-US">-lpthread</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">选项。</span></p>
<p style="margin: 0cm 0cm 10pt" class="MsoNormal"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">与进程相比：</span></p>
<p style="margin: 0cm 0cm 10pt" class="MsoNormal"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">每个进程都拥有自己的数据段、代码段和堆栈段</span><span lang="EN-US">,</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">这就造成了进程在进行切换等操作时都需要有比较负责的上下文切换等动作。运行于一个进程中的多个线程，它们彼此之间使用相同的地址空间，共享大部分数据，启动一个线程所花费的空间远远小于启动一个进程所花费的空间，而且，线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。</span></p>
<p style="margin: 0cm 0cm 10pt" class="MsoNormal"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">先看一个简单的多线程的例子：</span></p>
<p style="margin: 0cm 0cm 10pt" class="MsoNormal"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">注意该例子会引起</span><span lang="EN-US">double free</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">的问题，是为了说明下线程共享堆的性质。</span></p>
<p style="margin: 0cm 0cm 10pt" class="MsoNormal">
<p style="margin: 0cm 0cm 10pt" class="MsoNormal"><span lang="EN-US"></span></p><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin"></p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #008000">//</span><span style="color: #008000">(gcc&nbsp;&#8211;o&nbsp;example&nbsp;example.c&nbsp;&#8211;lpthread)</span><span style="color: #008000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">pthread.h</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #0000ff">string</span><span style="color: #000000">.h</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">stdio.h</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />#include&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">unistd.h</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />&nbsp;<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />pthread_t&nbsp;ntid;<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />&nbsp;<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">void</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;thr_fn(</span><span style="color: #0000ff">void</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;arg)<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><br /><img id="Codehighlighter1_172_446_Open_Image" onclick="this.style.display='none'; Codehighlighter1_172_446_Open_Text.style.display='none'; Codehighlighter1_172_446_Closed_Image.style.display='inline'; Codehighlighter1_172_446_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_172_446_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_172_446_Closed_Text.style.display='none'; Codehighlighter1_172_446_Open_Image.style.display='inline'; Codehighlighter1_172_446_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_172_446_Closed_Text"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_172_446_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;c&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">char</span><span style="color: #000000">*</span><span style="color: #000000">)arg;<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memset(c,</span><span style="color: #000000">'</span><span style="color: #000000">a</span><span style="color: #000000">'</span><span style="color: #000000">,</span><span style="color: #000000">9</span><span style="color: #000000">);<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c[</span><span style="color: #000000">9</span><span style="color: #000000">]</span><span style="color: #000000">=</span><span style="color: #000000">0</span><span style="color: #000000">;<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img id="Codehighlighter1_261_291_Open_Image" onclick="this.style.display='none'; Codehighlighter1_261_291_Open_Text.style.display='none'; Codehighlighter1_261_291_Closed_Image.style.display='inline'; Codehighlighter1_261_291_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_261_291_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_261_291_Closed_Text.style.display='none'; Codehighlighter1_261_291_Open_Image.style.display='inline'; Codehighlighter1_261_291_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_261_291_Closed_Text">/**/</span><span id="Codehighlighter1_261_291_Open_Text"><span style="color: #008000">/*</span><span style="color: #008000">printf("ntid:&nbsp;%x\n",ntid);</span><span style="color: #008000">*/</span></span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000">"</span><span style="color: #000000">thread,pid:&nbsp;%d,&nbsp;tid:&nbsp;%x,&nbsp;%x:%s\n</span><span style="color: #000000">"</span><span style="color: #000000">,getpid(),pthread_self(),(unsigned&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">)arg,(unsigned&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">)c);<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep(</span><span style="color: #000000">2</span><span style="color: #000000">);<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;free(c);<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif"  alt="" />}</span></span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />&nbsp;<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;main()<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><br /><img id="Codehighlighter1_464_1002_Open_Image" onclick="this.style.display='none'; Codehighlighter1_464_1002_Open_Text.style.display='none'; Codehighlighter1_464_1002_Closed_Image.style.display='inline'; Codehighlighter1_464_1002_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_464_1002_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_464_1002_Closed_Text.style.display='none'; Codehighlighter1_464_1002_Open_Image.style.display='inline'; Codehighlighter1_464_1002_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_464_1002_Closed_Text"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_464_1002_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;err;<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;p&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">char</span><span style="color: #000000">*</span><span style="color: #000000">)malloc(</span><span style="color: #000000">10</span><span style="color: #000000">);<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000">"</span><span style="color: #000000">main&nbsp;thread,pid:&nbsp;%d,&nbsp;tid:&nbsp;%x,&nbsp;%x\n</span><span style="color: #000000">"</span><span style="color: #000000">,getpid(),pthread_self(),(unsigned&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">)p);<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;err&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;pthread_create(</span><span style="color: #000000">&amp;</span><span style="color: #000000">ntid,&nbsp;NULL,&nbsp;thr_fn,(</span><span style="color: #0000ff">void</span><span style="color: #000000">*</span><span style="color: #000000">)p);</span><span style="color: #008000">//</span><span style="color: #008000">pthread.h</span><span style="color: #008000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /></span><span style="color: #000000"><br /><img id="Codehighlighter1_716_796_Open_Image" onclick="this.style.display='none'; Codehighlighter1_716_796_Open_Text.style.display='none'; Codehighlighter1_716_796_Closed_Image.style.display='inline'; Codehighlighter1_716_796_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_716_796_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_716_796_Closed_Text.style.display='none'; Codehighlighter1_716_796_Open_Image.style.display='inline'; Codehighlighter1_716_796_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(err</span><span style="color: #000000">!=</span><span style="color: #000000">0</span><span style="color: #000000">)&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_716_796_Closed_Text"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_716_796_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000">"</span><span style="color: #000000">exit\n</span><span style="color: #000000">"</span><span style="color: #000000">);<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(</span><span style="color: #000000">1</span><span style="color: #000000">);<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep(</span><span style="color: #000000">1</span><span style="color: #000000">);<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000">"</span><span style="color: #000000">main&nbsp;thread,pid:&nbsp;%d,&nbsp;tid:&nbsp;%x,&nbsp;%x:%s\n</span><span style="color: #000000">"</span><span style="color: #000000">,getpid(),pthread_self(),(unsigned&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">)p,(unsigned&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">)p);<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep(</span><span style="color: #000000">10</span><span style="color: #000000">);</span><span style="color: #008000">//</span><span style="color: #008000">等待线程结束</span><span style="color: #008000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /></span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;free(p);<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(</span><span style="color: #000000">0</span><span style="color: #000000">);<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif"  alt="" />}</span></span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span></div>
<p style="margin: 0cm 0cm 10pt" class="MsoNormal">感觉多线程编程可以和进程函数一起来看：</span></p>
<p style="margin: 0cm 0cm 10pt" class="MsoNormal"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">最基本的几个函数是如下几个：</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 10pt 36pt; tab-stops: list 36.0pt; mso-list: l1 level1 lfo1" class="MsoNormal"><span style="font-family: 'Wingdings 2'; mso-fareast-font-family: 'Wingdings 2'; mso-bidi-font-family: 'Wingdings 2'" lang="EN-US"><span style="mso-list: Ignore">&#223;<span style="font: 7pt 'Times New Roman'">&nbsp; </span></span></span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">线程标识</span><span lang="EN-US">: pthread_t pthread_self <span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;</span>pthread_equal</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 10pt 36pt; tab-stops: list 36.0pt; mso-list: l1 level1 lfo1" class="MsoNormal"><span style="font-family: 'Wingdings 2'; mso-fareast-font-family: 'Wingdings 2'; mso-bidi-font-family: 'Wingdings 2'" lang="EN-US"><span style="mso-list: Ignore">&#223;<span style="font: 7pt 'Times New Roman'">&nbsp; </span></span></span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">线程创建</span><span lang="EN-US">:pthrea_create</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 10pt 36pt; tab-stops: list 36.0pt; mso-list: l1 level1 lfo1" class="MsoNormal"><span style="font-family: 'Wingdings 2'; mso-fareast-font-family: 'Wingdings 2'; mso-bidi-font-family: 'Wingdings 2'" lang="EN-US"><span style="mso-list: Ignore">&#223;<span style="font: 7pt 'Times New Roman'">&nbsp; </span></span></span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">线程终止</span><span lang="EN-US">:pthread_exit pthread_join</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 10pt 36pt; tab-stops: list 36.0pt; mso-list: l1 level1 lfo1" class="MsoNormal"><span style="font-family: 'Wingdings 2'; mso-fareast-font-family: 'Wingdings 2'; mso-bidi-font-family: 'Wingdings 2'" lang="EN-US"><span style="mso-list: Ignore">&#223;<span style="font: 7pt 'Times New Roman'">&nbsp; </span></span></span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">线程取消</span><span lang="EN-US">:pthread_cancel</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 10pt 36pt; tab-stops: list 36.0pt; mso-list: l1 level1 lfo1" class="MsoNormal"><span style="font-family: 'Wingdings 2'; mso-fareast-font-family: 'Wingdings 2'; mso-bidi-font-family: 'Wingdings 2'" lang="EN-US"><span style="mso-list: Ignore">&#223;<span style="font: 7pt 'Times New Roman'">&nbsp; </span></span></span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">线程清理</span><span lang="EN-US">:pthread_cleanup_push pthread_cleanup_pop</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 10pt 36pt; tab-stops: list 36.0pt; mso-list: l1 level1 lfo1" class="MsoNormal"><span style="font-family: 'Wingdings 2'; mso-fareast-font-family: 'Wingdings 2'; mso-bidi-font-family: 'Wingdings 2'" lang="EN-US"><span style="mso-list: Ignore">&#223;<span style="font: 7pt 'Times New Roman'">&nbsp; </span></span></span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">线程分离属性</span><span lang="EN-US">:pthread_detach </span></p>
<p style="margin: 0cm 0cm 10pt" class="MsoNormal"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">很多书里都会讲到其用法。在</span><span lang="EN-US">/usr/include/pthread.h</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">下也可以直接看到其函数声明和基本的介绍。</span></p>
<p style="margin: 0cm 0cm 10pt" class="MsoNormal"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">这里只记录下我学习过程中觉得要注意的几个地方：</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 18pt; mso-add-space: auto; mso-list: l0 level1 lfo2" class="MsoListParagraphCxSpFirst"><span style="mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin" lang="EN-US"><span style="mso-list: Ignore">1.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span lang="EN-US">pthread_create</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">的参数介绍：</span><span lang="EN-US"><br />int pthread_create(pthread_t *tidp, const pthread_attr_t *attr, void *(*start_rtn)(void *),void *arg)</span></p>
<p style="margin: 0cm 0cm 0pt 18pt; mso-add-space: auto" class="MsoListParagraphCxSpMiddle"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">一个线程中调用</span><span lang="EN-US">pthread_create()</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">创建新的线程后，当前线程从</span><span lang="EN-US">pthread_create()</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">返回继续往下执行，而新的线程所执行的代码由我们传给</span><span lang="EN-US">pthread_create</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">的函数指针</span><span lang="EN-US">start_rtn</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">决定。</span><span lang="EN-US">start_rtn</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">函数接收一个参数，是通过</span><span lang="EN-US">pthread_create</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">的</span><span lang="EN-US">arg</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">参数传递给它的，该参数的类型为</span><span lang="EN-US">void *</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">，这个指针按什么类型解释由调用者自己定义。</span><span lang="EN-US">start_routine</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">的返回值类型也是</span><span lang="EN-US">void *</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">，这个指针的含义同样由调用者自己定义。</span><span lang="EN-US">start_routine</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">返回时，这个线程就退出了</span> <span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">。</span></p>
<p style="margin: 0cm 0cm 0pt 18pt; mso-add-space: auto" class="MsoListParagraphCxSpMiddle"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">注意如果</span><span lang="EN-US">tidp</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">是全局的变量，不要在子线程里使用它，因为可能子线程运行的时候，主线程还没有来得及给他赋值。这也是程序里我们打印子线程</span><span lang="EN-US">ID</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">用了</span><span lang="EN-US">pthread_self</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">而没有用</span><span lang="EN-US">ntid</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">的原因。</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 18pt; mso-add-space: auto; mso-list: l0 level1 lfo2" class="MsoListParagraphCxSpMiddle"><span style="mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin" lang="EN-US"><span style="mso-list: Ignore">2.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">如果</span> <span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">函数有返回值，注意对返回值的判断，例如</span><span lang="EN-US">create</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">时可能返回</span><span lang="EN-US">EAGAIN(</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">表示线程数目过多了</span><span lang="EN-US">)</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">，</span><span lang="EN-US">EINVAL(</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">表示属性值非法</span><span lang="EN-US">)</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">，</span><span lang="EN-US">join</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">时返回</span><span lang="EN-US">ESRCH(</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">表示没有那个线程，例如已经</span><span lang="EN-US">join</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">过一次了，线程资源被收回，这个线程</span><span lang="EN-US">id</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">也一起被回收，就会返回这个错误</span><span lang="EN-US">)</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">等等其他。感觉对以后学习线程属性是比较有用的，因为很多错误从线程属性上可以了解原因，同时加深对线程属性的理解。这些错误都可以通过</span><span lang="EN-US">man errno</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">来查看。</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 10pt 18pt; mso-add-space: auto; mso-list: l0 level1 lfo2" class="MsoListParagraphCxSpLast"><span style="mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin" lang="EN-US"><span style="mso-list: Ignore">3.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">线程</span><span lang="EN-US">id</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">的类型是</span><span lang="EN-US">pthread_t</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">，它只在当前进程中保证是唯一的，在不同的系统中</span><span lang="EN-US">pthread_t</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">这个类型有不同的实现，它可能是一个整数值，也可能是个结构体，地址等。不过查看</span><span lang="EN-US">/usr/include/bits/pthreadtypes.h</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">可以看到我的系统</span><span lang="EN-US">(ubuntu 10.04)</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">这里定义为</span><span lang="EN-US">: typedef unsigned long int pthread_t.</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">因此程序里我们直接用</span><span lang="EN-US">%x</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">打印其值。</span></p>
<p style="margin: 0cm 0cm 10pt" class="MsoNormal"><span lang="EN-US">ok</span><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin">了。接下来在写个关于线程终止，取消以及获得返回状态的例子。</span></p>
<p align="left">&nbsp;</p>
<p style="margin: 0cm 0cm 0pt" class="Publishwithline"><strong><span style="font-size: 1.2em"><span style="color: #17365d"><span lang="EN-US"><span style="font-family: Calibri"></span></span></span></span></strong></p><img src ="http://www.cppblog.com/izualzhy/aggbug/160022.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/izualzhy/" target="_blank">izualzhy</a> 2011-11-13 14:59 <a href="http://www.cppblog.com/izualzhy/archive/2011/11/13/160022.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>