﻿<?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>BlogJava-月光记忆-文章分类-c多线程学习</title><link>http://www.blogjava.net/sunzhong/category/41914.html</link><description>清泉响露</description><language>zh-cn</language><lastBuildDate>Mon, 05 Oct 2009 09:06:06 GMT</lastBuildDate><pubDate>Mon, 05 Oct 2009 09:06:06 GMT</pubDate><ttl>60</ttl><item><title>多线程编程学习笔记--信号量(转)</title><link>http://www.blogjava.net/sunzhong/articles/297096.html</link><dc:creator>月光记忆</dc:creator><author>月光记忆</author><pubDate>Fri, 02 Oct 2009 01:47:00 GMT</pubDate><guid>http://www.blogjava.net/sunzhong/articles/297096.html</guid><wfw:comment>http://www.blogjava.net/sunzhong/comments/297096.html</wfw:comment><comments>http://www.blogjava.net/sunzhong/articles/297096.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sunzhong/comments/commentRss/297096.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sunzhong/services/trackbacks/297096.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;信号量用在多线程多任务同步的，一个线程完成了某一个动作就通过信号量告诉别的线程，别的线程再进行某些动作（大家都在semtake的时候，就阻塞在 哪里）。而互斥锁是用在多线程多任务互斥的，一个线程占用了某一个资源，那么别的线程就无法访问，直到这个线程unlock，其他的线程才开始可以利用这 个资源。比如对全局变量的访问，有时要加锁，操作完了，在解锁。有的时候锁和信号量会同时使用的&#8221;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 也就是说，信号量不一定是锁定某一个资源，而是流程上的概念，比如：有A,B两个线程，B线程要等A线程完成某一任务以后再进行自己下面的步骤，这个任务 并不一定是锁定某一资源，还可以是进行一些计算或者数据处理之类。而线程互斥量则是&#8220;锁住某一资源&#8221;的概念，在锁定期间内，其他线程无法对被保护的数据进 行操作。在有些情况下两者可以互换。
<p><font size="3">两者之间的区别:</font></p>
<p><font size="3"><strong>作用域</strong><br />
<span style="color: rgb(153,204,0)">信号量</span>: 进程间或线程间(linux仅线程间的无名信号量pthread semaphore)<br />
<span style="color: rgb(255,0,0)">互斥锁</span>: 线程间</font></p>
<p><font size="3"><strong>上锁时&nbsp;</strong><br />
<span style="color: rgb(153,204,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;信号量</span>: 只要信号量的value大于0，其他线程就可以sem_wait成功，成功后信号量的value减一。若value值不大于0，则sem_wait使得线程阻塞，直到sem_post释放后value值加一,但是sem_wait返回之前还是会将此value值减一.<br />
<span style="color: rgb(255,0,0)">互斥锁</span>: 只要被锁住，其他任何线程都不可以访问被保护的资源</font></p>
<p><font size="3">以下是信号灯（量)的一些概念:</font></p>
<p><font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;信号灯与互斥锁和条件变量的主要不同在于&#8221;灯&#8221;的概念，灯亮则意味着资源可用，灯灭则意味着不可用。如果说后两中同步方式侧重于&#8221;等待&#8221;操作，即资 源不可用的话，信号灯机制则侧重于点灯，即告知资源可用；<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;没有等待线程的解锁或激发条件都是没有意义的，而没有等待灯亮的线程的点灯操作则有效，且能保持 灯亮状态。当然，这样的操作原语也意味着更多的开销。</font></p>
<p><font size="3">信号灯的应用除了灯亮/灯灭这种二元灯以外，也可以采用大于1的灯数，以表示资源数大于1，这时可以称之为多元灯。</font></p>
<p><font size="3">1． 创建和 注销</font></p>
<p><font size="3">POSIX信号灯标准定义了有名信号灯和无名信号灯两种，但LinuxThreads的实现仅有无名灯，同时有名灯除了总是可用于多进程之间以外，在使用上与无名灯并没有很大的区别，因此下面仅就无名灯进行讨论。</font></p>
<p><font size="3">int sem_init(sem_t *sem, int pshared, unsigned int value)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这是创建信号灯的API，其中value为信号灯的初值，pshared表示是否为多进程共享而不仅仅是用于一个进程。pshared不为０时此信号量在进程间共享，否则只能为当前进程的所有线程共享；value给出了信号量的初始值。LinuxThreads没有实现 多进程共享信号灯，因此所有非0值的pshared输入都将使sem_init()返回-1，且置errno为ENOSYS。初始化好的信号灯由sem变 量表征，用于以下点灯、灭灯操作。</font></p>
<p><font size="3">int sem_destroy(sem_t * sem)<br />
被注销的信号灯sem要求已没有线程在等待该信号灯，否则返回-1，且置errno为EBUSY。除此之外，LinuxThreads的信号灯 注销函数不做其他动作。<br />
<font face="Times New Roman" size="3"><em>sem_destroy destroys a semaphore object, freeing the resources it&nbsp; might&nbsp; hold.&nbsp; No&nbsp; threads&nbsp; should&nbsp; be&nbsp; waiting&nbsp; on&nbsp; the<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; semaphore&nbsp; at&nbsp; the&nbsp; time&nbsp; sem_destroy&nbsp; is&nbsp; called.&nbsp; In&nbsp; the&nbsp; LinuxThreads implementation, no resources are associated with<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; semaphore objects, thus sem_destroy actually does nothing except checking that no thread is waiting on the semaphore.</em><br />
</font><br />
</font></p>
<p><font size="3">2． 点灯和灭灯</font></p>
<p><font size="3">int sem_post(sem_t * sem)</font></p>
<p><font size="3">点灯操作将信号灯值原子地加1，表示增加一个可访问的资源。</font></p>
<p><font size="3">int sem_wait(sem_t * sem)<br />
int sem_trywait(sem_t * sem)</font></p>
<p><font size="3">sem_wait()为等待灯亮操作，等待灯亮（信号灯值大于0），然后将信号灯原子地减1，并返回。sem_trywait()为sem_wait()的非阻塞版，如果信号灯计数大于0，则原子地减1并返回0，否则立即返回-1，errno置为EAGAIN。</font></p>
<p><font size="3">3． 获取灯值</font></p>
<p><font size="3">int sem_getvalue(sem_t * sem, int * sval)</font></p>
<p><font size="3">读取sem中的灯计数，存于*sval中，并返回0。<br />
</font></p>
<p><font size="3"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr><wbr><wbr><wbr><wbr><span style="color: red">int sem_wait(sem_t * sem);<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> int sem_post(sem_t * sem);<br />
&nbsp;<wbr><br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 这两个函数都要用一个由sem_init调用初始化的信号量对象的指针做参数。<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> sem_post函数的作用是给信号量的值加上一个&#8220;1&#8221;，它是一个&#8220;原子操作&#8221;－－－即同时对同一个信号量做加&#8220;1&#8221;操作的两个线程是不会冲突的；而同时对同一个文件进行读、加和写操作的两个程序就有可能会引起冲突。信号量的值永远会正确地加一个&#8220;2&#8221;－－因为有两个线程试图改变它。<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> sem_wait函数也是一个原子操作，它的作用是从信号量的值减去一个&#8220;1&#8221;，但它永远会先等待该信号量为一个非零值才开始做减法。也就是说，如果你对一个值为2的信号量调用sem_wait(),线程将会继续执行，介信号量的值将减到1。如果对一个值为0的信号量调用sem_wait()，这个函数就会地等待直到有其它线程增加了这个值使它不再是0为止。如果有两个线程都在sem_wait()中等待同一个信号量变成非零值，那么当它被第三个线程增加一个&#8220;1&#8221;时，等待线程中只有一个能够对信号量做减法并继续执行，另一个还将处于等待状态。<br />
&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> 信号量这种&#8220;只用一个函数就能原子化地测试和设置&#8221;的能力下正是它的价值所在。还有另外一个信号量函数sem_trywait，它是sem_wait的非阻塞搭档。</span><br />
<br />
<br />
&nbsp;&nbsp; </p>
<p><font color="#003399">#include &lt;stdio.h&gt;<br />
#include &lt;unistd.h&gt;<br />
#include &lt;stdlib.h&gt;<br />
#include &lt;string.h&gt;<br />
#include &lt;pthread.h&gt;<br />
#include &lt;semaphore.h&gt;</font></p>
<p><font color="#003399">sem_t bin_sem;<br />
void *thread_function1(void *arg)<br />
{<br />
&nbsp;<wbr>printf("thread_function1--------------sem_wait\n");<br />
&nbsp;<wbr>sem_wait(&amp;bin_sem);<br />
&nbsp;<wbr>printf("sem_wait\n");<br />
&nbsp;<wbr>while (1)<br />
&nbsp;<wbr>{<br />
&nbsp;<wbr>}<br />
}</font></p>
<p><font color="#003399">void *thread_function2(void *arg)<br />
{<br />
&nbsp;<wbr>printf("thread_function2--------------sem_post\n");<br />
&nbsp;<wbr>sem_post(&amp;bin_sem);<br />
&nbsp;<wbr>printf("sem_post\n");<br />
&nbsp;<wbr>while (1)<br />
&nbsp;<wbr>{<br />
&nbsp;<wbr>}<br />
}</font></p>
<p><font color="#003399"><br />
&nbsp;<wbr><br />
int main()<br />
{<br />
&nbsp;<wbr>int res;<br />
&nbsp;<wbr>pthread_t a_thread;<br />
&nbsp;<wbr>void *thread_result;<br />
&nbsp;<wbr><br />
&nbsp;<wbr>res = sem_init(&amp;bin_sem, 0, 0);<br />
&nbsp;<wbr>if (res != 0)<br />
&nbsp;<wbr>{<br />
&nbsp;<wbr>&nbsp;<wbr>perror("Semaphore initialization failed");<br />
&nbsp;<wbr>}<br />
&nbsp;<wbr> printf("sem_init\n");<br />
&nbsp;<wbr>res = pthread_create(&amp;a_thread, NULL, thread_function1, NULL);<br />
&nbsp;<wbr>if (res != 0)<br />
&nbsp;<wbr>{<br />
&nbsp;<wbr>&nbsp;<wbr>perror("Thread creation failure");<br />
&nbsp;<wbr>}<br />
&nbsp;<wbr>printf("thread_function1\n");<br />
&nbsp;<wbr>sleep (5);<br />
&nbsp;<wbr>printf("sleep\n");<br />
&nbsp;<wbr>res = pthread_create(&amp;a_thread, NULL, thread_function2, NULL);<br />
&nbsp;<wbr>if (res != 0)<br />
&nbsp;<wbr>{<br />
&nbsp;<wbr>&nbsp;<wbr>perror("Thread creation failure");<br />
&nbsp;<wbr>}<br />
&nbsp;<wbr>while (1)<br />
&nbsp;<wbr>{<br />
&nbsp;<wbr>}<br />
}</font></p>
<p><br />
sem_init<br />
thread_function1<br />
thread_function1--------------sem_wait<br />
sleep<br />
thread_function2--------------sem_post<br />
sem_wait<br />
sem_post<br />
</p>
<p><br />
&nbsp;&nbsp;&nbsp;&nbsp;</font></p>
<img src ="http://www.blogjava.net/sunzhong/aggbug/297096.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sunzhong/" target="_blank">月光记忆</a> 2009-10-02 09:47 <a href="http://www.blogjava.net/sunzhong/articles/297096.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux系统下的多线程编程-条件变量(转)</title><link>http://www.blogjava.net/sunzhong/articles/296962.html</link><dc:creator>月光记忆</dc:creator><author>月光记忆</author><pubDate>Tue, 29 Sep 2009 18:42:00 GMT</pubDate><guid>http://www.blogjava.net/sunzhong/articles/296962.html</guid><wfw:comment>http://www.blogjava.net/sunzhong/comments/296962.html</wfw:comment><comments>http://www.blogjava.net/sunzhong/articles/296962.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sunzhong/comments/commentRss/296962.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sunzhong/services/trackbacks/296962.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有的时候仅仅依靠锁住共享资源来使用它是不够的。有时候共享资源只有某些状态的时候才能够使用。比方说，某个线程如果要从堆栈中读取数据，那么如果栈中没有数据就必须等待数据被压栈。这种情况下的同步使用互斥锁是不够的。另一种同步的方式－－条件变量，就可以使用在这种情况下。
<p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 条件变量的使用总是和互斥锁及共享资源联系在一起的。线程首先锁住互斥锁，然后检验共享资源的状态是否处于可使用的状态。如果不是，那么线程就要等待条件变量。要指向这样的操作就必须在等待的时候将互斥锁解锁，以便其他线程可以访问共享资源并改变其状态。它还得保证从等到得线程返回时互斥体是被上锁得。当另一个线程改变了共享资源的状态时，它就要通知正在等待条件变量的线程，使之重新变回被互斥锁阻塞的线程。<br />
&nbsp;&nbsp;&nbsp; </p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: red"><strong>其实，pthread中的条件变量的使用和目的与Java中的wait,notify类似.<br />
&nbsp;&nbsp;&nbsp;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #000000">假设有共享的资源sum,与之相关联的mutex 是lock_s.假设每个线程对sum的操作很简单的,与sum的状态无关,比如只是sum++.那么只用mutex足够了.程序员只要确保每个线程操作前,取得lock,然后sum++,再unlock即可.每个线程的代码将像这样<br />
</span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
　　 pthread_mutex_lock(lock_s);<br />
　　 sum++;<br />
　　 pthread_mutex_unlock(lock_s);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<span style="color: #000000"><br />
<br />
　　如果操作比较复杂,假设线程t0,t1,t2的操作是sum++,而线程t3则是在sum到达100的时候,打印出一条信息,并对sum清零.这种情况下,如果只用mutex, 则t3需要一个循环,每个循环里先取得lock_s,然后检查sum的状态,如果sum&gt;=100,则打印并清零,然后unlock.如果sum&lt;100,则unlock,并sleep()本线程合适的一段时间.</span></p>
<p><span style="color: #000000">　这个时候,t0,t1,t2的代码不变,t3的代码如下<br />
　　<span style="color: #ff0000">print()<br />
　　{<br />
　　　　while (1)<br />
　　　　{<br />
　　　　　　pthread_mutex_lock(lock_s);<br />
　　　　　　if(sum&gt;=100)<br />
　　　　　　{<br />
　　　　　　　　printf(&#8220;sum has reached 100!&#8221;);<br />
　　　　　　　　pthread_mutex_unlock(lock_s);<br />
　　　　　　}<br />
　　　　　　else<br />
　　　　　　{<br />
　　　　　　　　pthread_mutex_unlock(lock_s);<br />
　　　　　　　　my_thread_sleep(100);<br />
　　　　　　　　return OK;<br />
　　　　　　}<br />
　　　　}<br />
　　}<br />
</span></span><span style="color: #000000">这种办法有两个问题<br />
　　1) sum在大多数情况下不会到达100,那么对t3的代码来说,大多数情况下,走的是else分支,只是lock和unlock,然后sleep().这浪费了CPU处理时间.<br />
　　2) 为了节省CPU处理时间,t3会在探测到sum没到达100的时候sleep()一段时间.这样却又带来另外一个问题,亦即t3响应速度下降.可能在sum到达200的时候,t3才会醒过来.<br />
　　3) 这样,程序员在设置sleep()时间的时候陷入两难境地,设置得太短了节省不了资源,太长了又降低响应速度.真是难办啊!</span></p>
<p><span style="color: #000000">　　这个时候,condition variable外裤内穿,从天而降,拯救了焦头烂额的你.</span></p>
<p><span style="color: #000000">　　你首先定义一个condition variable.<br />
　　pthread_cond_t cond_sum_ready=PTHREAD_COND_INITIALIZER;</span></p>
<p><span style="color: #000000">　　t0,t1,t2的代码只要后面加两行,像这样<br />
　　<span style="color: #ff0000">add()<br />
　　{<br />
　　　　pthread_mutex_lock(lock_s);<br />
　　　　sum++;<br />
　　　　pthread_mutex_unlock(lock_s);<br />
　　　　if(sum&gt;=100)<br />
　　　　pthread_cond_signal(&amp;cond_sum_ready);<br />
　　}<br />
</span>　　而t3的代码则是<br />
　　<span style="color: #ff0000">print<br />
　　{<br />
　　　　pthread_mutex_lock(lock_s);<br />
　　　　while(sum&lt;100)<br />
　　　　pthread_cond_wait(&amp;cond_sum_ready, &amp;lock_s);<br />
　　　　printf(&#8220;sum is over 100!&#8221;);<br />
　　　　sum=0;<br />
　　　　pthread_mutex_unlock(lock_s);<br />
　　　　return OK;<br />
　　}<br />
</span></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp; 注意两点:<br />
　　1) 在thread_cond_wait()之前,必须先lock相关联的mutex, 因为假如目标条件未满足,pthread_cond_wait()实际上会unlock该mutex, 然后block,当目标变量被唤醒的时候才会再重新lock该mutex, 然后返回.</span></p>
<p><span style="color: #000000">　　2) 为什么是while(sum&lt;100),而不是if(sum&lt;100) ?这是因为在pthread_cond_signal()和pthread_cond_wait()返回之间,有时间差,假设在这个时间差内,还有另外一个线程t4又把sum减少到100以下了,那么t3在pthread_cond_wait()返回之后,显然应该再检查一遍sum的大小.这就是用while的用意,如果sum减少到了100以下,就会再次进入pthread_cond_wait方法.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #ff0000">条件变量使我们可以睡眠等待某种条件出现。<br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 条件变量是利用线程间共享的全局变量进行同步的一种机制，主要包括两个动作：一个线程等待"条件变量的激活"而挂起；另一个线程使"条件变量激活"。为了防止竞争，条件变量的使用总是和一个互斥锁结合在一起。<br />
条件变量类型为pthread_cond_t</p>
<p>整个pthread_cond_wait（＆mycond,&amp;mymutex）函数的工作流程：<br />
第一个线程首先调用：<br />
&nbsp;&nbsp;&nbsp; pthread_mutex_lock(&amp;mymutex);<br />
然后，它检查了列表。没有找到感兴趣的东西，于是它调用：<br />
&nbsp;&nbsp;&nbsp; pthread_cond_wait(&amp;mycond, &amp;mymutex);<br />
然后，pthread_cond_wait() 调用在返回前执行许多操作：<br />
&nbsp;&nbsp;&nbsp; pthread_mutex_unlock(&amp;mymutex);<br />
它对 mymutex 解锁，然后进入睡眠状态，等待 mycond 以接收 POSIX 线程&#8220;信号&#8221;。一旦接收到&#8220;信号&#8221;（加引号是因为我们并不是在讨论传统的 UNIX 信号，而是来自 pthread_cond_signal() 或 pthread_cond_broadcast() 调用的信号），它就会苏醒。但 pthread_cond_wait() 没有立即返回 -- 它还要做一件事：重新锁定 mutex：<br />
&nbsp;&nbsp;&nbsp; pthread_mutex_lock(&amp;mymutex);<br />
pthread_cond_wait() 知道我们在查找 mymutex &#8220;背后&#8221;的变化，因此它继续操作，为我们锁定互斥对象，然后才返回。（以上步骤全为原子操作）</p>
<p>&nbsp;</p>
<p>创建和注销<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;条件变量和互斥锁一样，都有静态动态两种创建方式，静态方式使用PTHREAD_COND_INITIALIZER常量，如下：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_cond_t cond=PTHREAD_COND_INITIALIZER<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;动态方式调用pthread_cond_init()函数，API定义如下：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;尽管POSIX标准中为条件变量定义了属性，但在LinuxThreads中没有实现，因此cond_attr值通常为NULL，且被忽略。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;注销一个条件变量需要调用pthread_cond_destroy()，只有在没有线程在该条件变量上等待的时候才能注销这个条件变量，否则返回EBUSY。API定义如下：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int pthread_cond_destroy(pthread_cond_t *cond)</p>
<p><br />
等待和激发<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;等待条件有两种方式：无条件等待pthread_cond_wait()和计时等待pthread_cond_timedwait()，其中计时等待方式如果在给定时刻前条件没有满足，则返回ETIMEOUT，结束等待，其中abstime以与time()系统调用相同意义的绝对时间形式出现，0表示格林尼治时间1970年1月1日0时0分0秒。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用绝对时间而非相对时间的优点是。如果函数提前返回（很可能因为捕获了一个信号，）<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 无论哪种等待方式，都必须和一个互斥锁配合，以防止多个线程同时请求pthread_cond_wait()（或pthread_cond_timedwait()，下同）的竞争条件（Race Condition）。mutex互斥锁必须是普通锁（PTHREAD_MUTEX_TIMED_NP）或者适应锁（PTHREAD_MUTEX_ADAPTIVE_NP），且在调用pthread_cond_wait()前必须由本线程加锁（pthread_mutex_lock()），而在更新条件等待队列以前，mutex保持锁定状态，并在线程挂起进入等待前解锁。在条件满足从而离开 pthread_cond_wait()之前，mutex将被重新加锁，以与进入pthread_cond_wait()前的加锁动作对应。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;激发条件有两种形式，pthread_cond_signal()激活一个等待该条件的线程，存在多个等待线程时按入队顺序激活其中一个；而pthread_cond_broadcast()则激活所有等待线程。</p>
<p><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pthread_cond_wait()和pthread_cond_timedwait() 都被实现为取消点，因此，在该处等待的线程将立即重新运行，在重新锁定mutex后离开pthread_cond_wait()，然后执行取消动作。也就是说如果pthread_cond_wait()被取消，mutex是保持锁定状态的，因而需要定义退出回调函数来为其解锁。</p>
<p>以下示例集中演示了互斥锁和条件变量的结合使用，以及取消对于条件等待动作的影响。在例子中，有两个线程被启动，并等待同一个条件变量，如果不使用退出回 调函数（见范例中的注释部分），则tid2将在pthread_mutex_lock()处永久等待。如果使用回调函数，则tid2的条件等待及主线程的 条件激发都能正常工作。</p>
<p>#include &lt;stdio.h&gt;<br />
#include &lt;pthread.h&gt;<br />
#include &lt;unistd.h&gt;<br />
pthread_mutex_t mutex;<br />
pthread_cond_t&nbsp; cond;<br />
<br />
void * child1(void *arg)<br />
{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; pthread_cleanup_push(pthread_mutex_unlock,&amp;mutex);&nbsp; /* comment 1 */&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;while(1){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("thread 1 get running \n");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("thread 1 pthread_mutex_lock returns %d\n",pthread_mutex_lock(&amp;mutex));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sleep(5);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pthread_cond_wait(&amp;cond,&amp;mutex);&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("thread 1 condition applied\n");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pthread_mutex_unlock(&amp;mutex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;pthread_cleanup_pop(0);&nbsp;&nbsp;&nbsp;&nbsp; /* comment 2 */<br />
}<br />
<br />
void *child2(void *arg){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(1){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sleep(3);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* comment 3 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("thread 2 get running.\n");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("thread 2 pthread_mutex_lock returns %d\n",pthread_mutex_lock(&amp;mutex));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pthread_cond_wait(&amp;cond,&amp;mutex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("thread 2 condition applied\n");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pthread_mutex_unlock(&amp;mutex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sleep(1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
}<br />
<br />
int main(void){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int tid1,tid2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("hello, condition variable test\n");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pthread_mutex_init(&amp;mutex,NULL);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pthread_cond_init(&amp;cond,NULL);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pthread_create(&amp;tid1,NULL,child1,NULL);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pthread_create(&amp;tid2,NULL,child2,NULL);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sleep(2);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* comment 4 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pthread_cancel(tid1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* comment 5 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sleep(2);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* comment 6 */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pthread_cond_signal(&amp;cond);&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }while(1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep(100);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pthread_exit(0);<br />
} </p>
<p><br />
&nbsp;&nbsp;&nbsp;&nbsp; 如果不做注释5的pthread_cancel()动作，即使没有那些sleep()延时操作，child1和child2都能正常工作。注释3和注释4 的延迟使得child1有时间完成取消动作，从而使child2能在child1退出之后进入请求锁操作。如果没有注释1和注释2的回调函数定义，系统将 挂起在child2请求锁的地方；而如果同时也不做注释3和注释4的延时，child2能在child1完成取消动作以前得到控制，从而顺利执行申请锁的 操作，但却可能挂起在pthread_cond_wait()中，因为其中也有申请mutex的操作,同时child1没有释放mutex就退出了。child1函数给出的是标准的条件变量的使用方 式：回调函数保护，等待条件前锁定，pthread_cond_wait()返回后解锁。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 条件变量机制不是异步信号安全的，也就是说，在信号处理函数中调用pthread_cond_signal()或者pthread_cond_broadcast()很可能引起死锁。</p>
<p>&nbsp;</p>
<p><br />
&nbsp;</p>
<p></span>&nbsp;</p>
<p>&nbsp;</p>
<p><br />
</p>
</strong></span>
<img src ="http://www.blogjava.net/sunzhong/aggbug/296962.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sunzhong/" target="_blank">月光记忆</a> 2009-09-30 02:42 <a href="http://www.blogjava.net/sunzhong/articles/296962.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多线程编程学习笔记—互斥量(转)</title><link>http://www.blogjava.net/sunzhong/articles/296958.html</link><dc:creator>月光记忆</dc:creator><author>月光记忆</author><pubDate>Tue, 29 Sep 2009 16:18:00 GMT</pubDate><guid>http://www.blogjava.net/sunzhong/articles/296958.html</guid><wfw:comment>http://www.blogjava.net/sunzhong/comments/296958.html</wfw:comment><comments>http://www.blogjava.net/sunzhong/articles/296958.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sunzhong/comments/commentRss/296958.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sunzhong/services/trackbacks/296958.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 一、什么是互斥锁&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 另一种在多线程程序中同步访问手段是使用互斥量。程序员给某个对象加上一把&#8220;锁&#8221;，每次只允许一个线程去访问它。如果想对代码关键部分的访问进行控制，你必须在进入这段代码之前锁定一把互斥量，在完成操作之后再释放它。&nbsp;&nbsp;&nbsp;&nbsp;&n...&nbsp;&nbsp;<a href='http://www.blogjava.net/sunzhong/articles/296958.html'>阅读全文</a><img src ="http://www.blogjava.net/sunzhong/aggbug/296958.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sunzhong/" target="_blank">月光记忆</a> 2009-09-30 00:18 <a href="http://www.blogjava.net/sunzhong/articles/296958.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>