理解 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> &nbsp;
include <sys/time.h> &nbsp;
include <unistd.h> &nbsp;
include <pthread.h> &nbsp;
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。

相关推荐