信号量与条件变量的区别

注意信号量与条件变量的区别

信号量内容可见:http://www.cnblogs.com/charlesblc/p/6142868.html
 
信号量、共享内存,以及消息队列等System V IPC三剑客主要关注 进程间通讯
而条件变量、互斥锁,主要关注 线程间通讯
 
 
pthread_cond_wait指的是 条件变量,总和一个 互斥锁结合使用。在 调用pthread_cond_wait前要先获取锁。pthread_cond_wait函数执行时先 自动释放指定的锁,而后等待条件变量的变化。在函数调用返回以前,自动将指定的互斥量 从新锁住
 

int pthread_cond_signal(pthread_cond_t * cond);html

pthread_cond_signal经过条件变量cond发送消息,若多个消息在等待,它只唤醒一个函数

pthread_cond_broadcast能够唤醒全部。调用pthread_cond_signal后要 马上释放互斥锁,由于pthread_cond_wait的最后一步是要将指定的互斥量从新锁住,若是pthread_cond_signal以后没有释放互斥锁,pthread_cond_wait仍然要阻塞。
 
 
不管哪一种等待方式,都必须和一个互斥锁配合,以防止多个线程同时请求pthread_cond_wait()(或pthread_cond_timedwait(),下同)的竞争条件(Race   Condition)。mutex互斥锁必须是普通锁(PTHREAD_MUTEX_TIMED_NP)或者适应锁 (PTHREAD_MUTEX_ADAPTIVE_NP)
互斥锁的类型,有如下几种:

  PTHREAD_MUTEX_TIMED_NP,这是缺省值,也就是普通锁。当一个线程加锁之后,其他请求锁的线程将造成一个等待队列,并在解锁后按优先级得到锁。这种锁策略保证了资源分配的公平性。

  PTHREAD_MUTEX_RECURSIVE_NP,嵌套锁,容许同一个线程对同一个锁成功得到屡次,并经过屡次unlock解锁。若是是不一样线程请求,则在加锁线程解锁时从新竞争。

  PTHREAD_MUTEX_ERRORCHECK_NP,检错锁,若是同一个线程请求同一个锁,则返回EDEADLK,不然与PTHREAD_MUTEX_TIMED_NP类型动做相同。这样就保证当不容许屡次加锁时不会出现最简单状况下的死锁。

  PTHREAD_MUTEX_ADAPTIVE_NP,适应锁,动做最简单的锁类型,仅等待解锁后从新竞争。

且在调用pthread_cond_wait()前必须由本线程加锁 (pthread_mutex_lock()),而在更新条件等待队列之前,mutex保持锁定状态,并在线程挂起进入等待前解锁。在条件知足从而离开 pthread_cond_wait()以前,mutex将被从新加锁,以与进入pthread_cond_wait()前的加锁动做对应。  性能

 
激发条件有两种形式,pthread_cond_signal()激活一个等待该条件的线程,存在多个等待线程时按入队顺序激活其中一个;而pthread_cond_broadcast()则激活全部等待线程。
 

下面是另外一处说明:给出了函数运行全过程。 为何在唤醒线程后要从新mutex加锁?ui

了解 pthread_cond_wait() 的做用很是重要 -- 它是 POSIX 线程信号发送系统的核心,也是最难以理解的部分。
首先,让咱们考虑如下状况:线程为查看已连接列表而锁定了互斥对象,然而该列表恰巧是空的。这一特定线程什么也干不了 -- 其设计意图是从列表中除去节点,可是如今却没有节点。所以,它只能:

锁定互斥对象时,线程将调用 pthread_cond_wait(&mycond,&mymutex)。
 
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() 调用中)如今将 苏醒是先解锁仍是先signal,各有优缺点,下文会分析另外注意,signal的函数里面是否是解锁加锁的,跟wait不同。
 
如今,看一下第一个线程发生了什么。您可能会认为在 2 号线程调用 pthread_cond_broadcast(&mymutex) 以后,1 号线程的 pthread_cond_wait() 会当即返回。不是那样!实际上,pthread_cond_wait() 将执行最后一个操做: 从新锁定 mymutex。一旦 pthread_cond_wait() 锁定了互斥对象,那么它将返回并容许 1 号线程继续执行。那时,它能够立刻检查列表,查看它所感兴趣的更改。 实际上,通常是先解锁。
 
来看一个例子:
In Thread1:
pthread_mutex_lock(&m_mutex);   
pthread_cond_wait(&m_cond,&m_mutex);   
pthread_mutex_unlock(&m_mutex);  
 
In Thread2:
pthread_mutex_lock(&m_mutex);   
pthread_cond_signal(&m_cond);   
pthread_mutex_unlock(&m_mutex);  

 

为何要与pthread_mutex 一块儿使用呢?spa

这是为了应对 线程1在调用pthread_cond_wait()但线程1尚未进入wait cond的状态的时候,此时线程2调用了 cond_singal 的状况。 若是不用mutex锁的话,这个cond_singal就丢失了。加了锁的状况是,线程2必须等到 mutex 被释放(也就是 pthread_cod_wait() 释放锁并进入wait_cond状态 ,此时线程2上锁) 的时候才能调用cond_singal.
 

pthread_cond_signal便可以放在pthread_mutex_lock和pthread_mutex_unlock之间,也能够放在pthread_mutex_lock和pthread_mutex_unlock以后,可是各有有缺点。

 
之间:
pthread_mutex_lock
    xxxxxxx
pthread_cond_signal
pthread_mutex_unlock
缺点:在某下线程的实现中,会形成等待线程从内核中唤醒(因为cond_signal)而后又回到内核空间(由于 cond_wait返回后会有原子加锁的 行为)(注:意思是说这时候signal的线程尚未unlock,因此wait的线程加锁会致使堵塞,并进入内核),因此一来一回会有性能的问题。可是在LinuxThreads或者NPTL里面,就不会有这个问题,由于在Linux 线程中,有两个队列,分别是 cond_wait队列和mutex_lock队列, cond_signal只是让线程从cond_wait队列移到mutex_lock队列,而不用返回到用户空间,不会有性能的损耗。
因此在Linux中推荐使用这种模式。
 
 
以后:
pthread_mutex_lock
    xxxxxxx
pthread_mutex_unlock
pthread_cond_signal
优势:不会出现以前说的那个潜在的性能损耗,由于在signal以前就已经释放锁了
缺点:若是unlock和signal以前,有个 低优先级的线程正在mutex上等待的话,那么这个低优先级的线程就会抢占高优先级的线程(cond_wait的线程),而这在上面的放中间的模式下是不会出现的。
相关文章
相关标签/搜索