与互斥锁不同,条件变量是用来等待而不是用来上锁的。条件变量用来自动阻塞一个线程,直到某特殊情况发生为止。条件变量使我们可以睡眠等待某种条件出现。
条件变量是利用线程间共享的全局变量进行同步的一种机制,
主要包括两个动作:
一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。
条件的检测是在互斥锁的保护下进行的。如果条件为假,一个线程自动阻塞,并释放等待状态改变的互斥锁。
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()则激活所有等待线程(惊群)。
例子:
#include <stdio.h>
#include <pthread.h>
int iCount = 0;
pthread_mutex_t mutex;
pthread_cond_t lock_cond;
void Addfunc(int _iNum)
{
pthread_mutex_lock(&mutex);
printf("now pthread %d add\n", _iNum);
iCount++;
printf("iCount = %d\n", iCount);
pthread_mutex_unlock(&mutex);
if(iCount >= 20)
{
pthread_cond_signal(&lock_cond);
}
}
Pth1_func(void * _pcBuffer)
{
int i = 1;
while(1)
{
Addfunc(i);
sleep(1);
}
}
Pth2_func(void * _pcBuffer)
{
int i = 2;
while(1)
{
Addfunc(i);
sleep(1);
}
}
Pth3_func(void * _pcBuffer)
{
pthread_mutex_lock(&mutex);
while(iCount < 20)
{
pthread_cond_wait(&lock_cond, &mutex); //程序第一次运行到此,进行阻塞此线程,解锁
//接收到信号后,线程继续运行,加锁
printf("iCount over 20, %d\n", iCount);
iCount = 0;
printf("pthread 3 iCount= %d\n", iCount);
}
pthread_mutex_unlock(&mutex);
}
int main(int argc, char * argv [ ])
{
int iRet = 0;
pthread_t pthread1;
pthread_t pthread2;
pthread_t pthread3;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&lock_cond, NULL);
printf("start create pthread\n");
iRet = pthread_create(&pthread1, NULL, (void *)&Pth1_func, NULL);
if(iRet)
{
printf("creat pth_1 error\n");
}
iRet = pthread_create(&pthread2, NULL, (void *)&Pth2_func, NULL);
if(iRet)
{
printf("creat pth_2 error\n");
}
iRet = pthread_create(&pthread3, NULL, (void *)&Pth3_func, NULL);
if(iRet)
{
printf("creat pth_3 error\n");
}
pthread_join(pthread1, NULL);
pthread_join(pthread2, NULL);
pthread_join(pthread3, NULL);
return 1;
}
当程序运行到函数Pth3_func时,线程进行阻塞,并且解锁,此时执行线程Pth2_func和Pth1_func,对全局变量进行加一操作,当全局变量iCount的值>=20时,发送信号,使线程Pth3_func函数加锁,继续运行。