理解 Linux 条件变量
1 简介
当多个线程之间因为存在某种依赖关系,导致只有当某个条件存在时,才可以执行某个线程,此时条件变量(pthread_cond_t)可以派上用场。比如:
例1: 当系统不忙(这是一个条件)时,执行扫描文件状态的线程。
例2: 多个线程组成线程池,只有当任务队列中存在任务时,才用其中一个线程去执行这个任务。为避免惊群(thrundering herd),可以采用条件变量同步线程池中的线程。
2 用法
条件变量(pthread_cond_t)必须与锁(pthread_mutex_t)一起使用。
条件变量的API:
1) pthread_cond_init
2) pthread_cond_signal / pthread_cond_broadcast
3) pthread_cond_wait / pthread_cond_timedwait
4) pthread_cond_destroy
线程A:
include <stdio.h>
include <sys/time.h>
include <unistd.h>
include <pthread.h>
include <errno.h>
...
void A_thread_run(void *arg)
{
...
pthread_mutex_lock (& lock);
// 条件满足, 发出通知
pthread_cond_signal (& cond);
pthread_mutex_unlock (& lock);
...
}
线程B:
void B_thread_run(void *arg)
{
for ( ; ; ) {
pthread_mutex_lock (&lock);
/* pthread_cond_wait 原子调用: 等待条件变量, 解除锁, 然后阻塞
* 当 pthread_cond_wait 返回,则条件变量有信号,同时上锁
*
* 等待条件有两种方式:条件等待pthread_cond_wait()和计时等待pthread_cond_timedwait(),
* 其中计时等待方式如果在给定时刻前条件没有满足,则返回ETIMEOUT
* 无论哪种等待方式,都必须和一个互斥锁配合,以防止多个线程同时请求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()前的加锁动作对应。
* 激发条件有两种形式,pthread_cond_signal()激活一个等待该条件的线程,存在多个等待线程时按入队顺序激活其中一个;
* 而pthread_cond_broadcast()则激活所有等待线程(惊群)。
*/
pthread_cond_wait (&cond, &lock);
if (shutdown) {
break;
}
/* Unlock */
pthread_mutex_unlock (&lock);
/* do your task here */
}
pthread_mutex_unlock (&lock);
pthread_exit (0);
}
线程B调用pthread_cond_wait,从而阻塞在此句,等待有信号通知。pthread_cond_wait内部存在原子调用:解除锁和等待条件变量有信号。当pthread_cond_wait函数返回,表明得到了信号通知,同时上锁。
线程A用pthread_cond_signal通知调用了pthread_cond_wait的线程B。