如果一个线程的某个共享变量的状态发生变化,条件变量会通知其他线程,并让其他线程等待。
条件变量的数据类型是pthread_cond_t,使用条件变量前必须对其进行初始化。如同互斥量一样,条件变量的创建方式也有两种:静态分配、动态创建。将经由静态分配的条件变量赋值为PTHREAD_COND_INITIALIZER就完成了初始化操作。我们也可以使用pthread_cond_init函数动态初始化条件变量。条件变量初始化函数如代码清单1-17所示。
代码清单1-17 条件变量初始化函数
cond参数表示将要初始化的条件变量对象。尽管POSIX标准中为条件变量定义了属性,但在LinuxThreads中没有实现cond_attr所指向的pthread_condattr_t类型对象,因此cond_attr的值通常为NULL。
pthread_cond_wait函数用于阻塞当前线程,等待其他的线程调用pthread_cond_signal函数或pthread_cond_broadcast函数来唤醒它。pthread_cond_wait函数必须与pthread_mutex配套使用,在调用pthread_cond_wait函数之前必须先通过pthread_mutex_lock函数拿到互斥量的锁对象。pthread_cond_wait函数一进入wait状态就会自动释放mutex。当其他线程通过通知将该线程唤醒时,pthread_cond_wait函数又自动获得互斥量的锁对象。条件变量等待函数如代码清单1-18所示。
代码清单1-18 条件变量等待函数
pthread_cond_timedwait函数可以设定等待时间abstime,系统会按照abstime来设置一个高精度的定时器,时间到了定时器会自动触发通知,唤醒等待的线程。
pthread_cond_signal函数的作用是发送一个信号给另外一个正处于阻塞状态的线程,使其从阻塞状态中醒过来继续执行,条件变量通知函数如代码清单1-19所示。如果没有线程处于阻塞等待状态,则pthread_cond_signal也会成功返回。
代码清单1-19 条件变量通知函数
pthread_cond_signal函数只会给一个线程发送信号,如果有多个线程正在阻塞等待同一个条件变量,会优先通知高优先级的线程执行。如果各等待线程优先级相同,则根据等待时间的长短来确定由哪个线程执行。pthread_cond_broadcast函数会唤醒等待在同一条件变量上的所有线程,但由于唤醒后最终只有一个线程能获取到锁,所以最终仍只有一个线程能立即执行。pthread_cond_signal函数相当于Java的Object.notifyAll()功能。
代码清单1-20是一个条件变量使用的简单示例。该示例首先定义了一个数据减小的函数decrement,decrement在count的值没有到达5之前,会一直调用pthread_cond_wait函数,让当前线程处于阻塞状态。接着定义了数据增加函数increment,通过for循环将count的值增加到5。增加到5以后会调用pthread_cond_signal函数发送通知给decrement。decrement收到通知后会从等待中醒来,接着让数据循环相减。这样就实现了数据从0~5增加,以及从5~0减少的过程。
代码清单1-20 条件变量使用示例
在调用条件信号操作(pthread_cond_wait()、pthread_cond_signal())之前都必须调用pthread_mutex_lock进行加锁,并在调用结束后调用pthread_mutex_unlock进行解锁。