条件变量详解

https://www.ibm.com/developerworks/cn/linux/thread/posix_thread3/#1

 

在 上一篇文章结束时,我描述了一个比较特殊的难题:如果线程正在等待某个特定条件发生,它应该如何处理这种情况?它可以重复对互斥对象锁定和解锁,每次都会检查共享数据结构,以查找某个值。但这是在浪费时间和资源,而且这种繁忙查询的效率非常低。解决这个问题的最佳方法是使用 pthread_cond_wait() 调用来等待特殊条件发生。
了解 pthread_cond_wait() 的作用非常重要 -- 它是 POSIX 线程信号发送系统的核心,也是最难以理解的部分。
首先,让我们考虑以下情况:线程为查看已链接列表而锁定了互斥对象,然而该列表恰巧是空的。这一特定线程什么也干不了 -- 其设计意图是从列表中除去节点,但是现在却没有节点。因此,它只能:
锁定互斥对象时,线程将调用 pthread_cond_wait(&mycond,&mymutex)。pthread_cond_wait() 调用相当复杂,因此我们每次只执行它的一个操作。
pthread_cond_wait() 所做的第一件事就是同时对互斥对象解锁(于是其它线程可以修改已链接列表),并等待条件 mycond 发生(这样当 pthread_cond_wait() 接收到另一个线程的“信号”时,它将苏醒)。现在互斥对象已被解锁,其它线程可以访问和修改已链接列表,可能还会添加项。
此时,pthread_cond_wait() 调用还未返回。对互斥对象解锁会立即发生,但等待条件 mycond 通常是一个阻塞操作,这意味着线程将睡眠,在它苏醒之前不会消耗 CPU 周期。这正是我们期待发生的情况。线程将一直睡眠,直到特定条件发生,在这期间不会发生任何浪费 CPU 时间的繁忙查询。从线程的角度来看,它只是在等待 pthread_cond_wait() 调用返回。
现在继续说明,假设另一个线程(称作“2 号线程”)锁定了 mymutex 并对已链接列表添加了一项。在对互斥对象解锁之后,2 号线程会立即调用函数 pthread_cond_broadcast(&mycond)。此操作之后,2 号线程将使所有等待 mycond 条件变量的线程立即苏醒。这意味着第一个线程(仍处于 pthread_cond_wait() 调用中)现在将苏醒。

现在,看一下第一个线程发生了什么。您可能会认为在 2 号线程调用 pthread_cond_broadcast(&mymutex) 之后,1 号线程的 pthread_cond_wait() 会立即返回。不是那样!实际上,pthread_cond_wait() 将执行最后一个操作:重新锁定 mymutex。一旦 pthread_cond_wait() 锁定了互斥对象,那么它将返回并允许 1 号线程继续执行。那时,它可以马上检查列表,查看它所感兴趣的更改。

 

 

http://blog.chinaunix.net/uid-20628302-id-1608577.html

 

下面说一下,pthread_cond_wait(&mycond,&mymutex)的东西
1. 设计pthread_cond_wait 的初衷


   线程如果需要等待某个条件发生,它该作何处理呢?它可以重复对互斥对象锁定和解锁,每次都会检查共享元素,以查找某个值。这样会比较浪费cpu的时钟周期。而且效率比较低,何不借鉴一下dma的处理办法,等待某个条件发生了通知一下,这样cpu就可以处理自己的事了,我想pthread_cond_wait的初衷就是这样的,也是这样被设计出来的。如果你有不同解释可以通知我,我们可以共同讨论。


2. pthread_cond_wait的内部操作
   在调用之前需要锁定互斥对象,然后再调用pthread_cond_wait。
  1> pthread_cond_wait所做的第一件事就是同时对互斥对象解锁(这样其它线程就可以修改共享对象了,操作之前不要忘记加锁哦)。
  2> 等待条件通常是一个阻塞操作(这一点有点不明白,为什么是通常,难道说是还有其它动作,有知道的可以告诉我啊),这意味着线程将睡眠,在它苏醒之前不会消耗cpu周期(这正是我们想要的).线程睡呀睡呀,直到,有人叫它, 比如:另一个线程锁定了mymutex,并对共享对象对了某个动作.在对互斥对象解锁之后(this is very important),2号线程会立即调用函数pthread_cond_broadcast(&mycond)(这个地方也有点不明白, 我想不一定需要立即调用pthread_cond_broadcast,日比如有一个共享的线程数目 pthread_num = 5,当创建一个线程的时候pthread_num++,但是当该线程结束的时候pthread_num--,如果这个数小于5,我们就可以广播一下这个事件,激活一个线程,用以创建更多的线程)。
  3> 调用pthread_cond_wait的线程被叫醒之后,将重新锁定mymutex,之后才返回。


下面画个图来表示一下期间锁的调用(是伪码)


lock(mutex)   ----------------a.lock
pthread_cond_wait()
{
    unlock(mutex)-------------a.unlock
    if ( 条件不满足)
      睡觉
    else 
    {
      lock(mutex)-------------b.lock /条件成立后 内部锁定了 mutex 和后面的 b.unlock 对应
      return
    }
}


dosomething();


unlock(mutex);---------------b.unlock


这样就可以看出来锁的调用了吧。

你可能感兴趣的:(C语言,Linux,网络通信和多线程)