条件变量本身不是锁!但它也可以造成线程阻塞。通常与互斥锁配合使用。给多线程提供一个会合的场所(共享的数据)。主要应用函数:
pthread_cond_init函数 pthread_cond_destroy函数
pthread_cond_wait函数 pthread_cond_timedwait函数
pthread_cond_signal函数 pthread_cond_broadcast函数
以上6 个函数的返回值都是:成功返回0, 失败直接返回错误号。
pthread_cond_t类型 用于定义条件变量 pthread_cond_t cond;
引入条件变量的目的:在使用互斥锁的基础上引入条件变量可以使程序的效率更高,因为条件变量的引入明显减少了线程取竞争互斥锁的次数。执行pthread_cond_wait或pthread_cond_timedwait函数的线程明显知道了条件不满足,要因此在其释放锁之后就没有必要再跟其它线程去竞争锁了,只需要阻塞等待signal或broadcast函数将其唤醒。这样提高了效率。
(1)pthread_cond_init函数
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
作用:初始化一个条件变量
参2:attr表条件变量属性,通常为默认值,传NULL即可。也可以使用静态初始化的方法,初始化条件变量:pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
(2)pthread_cond_destroy函数
int pthread_cond_destroy(pthread_cond_t *cond);
作用:销毁一个条件变量
(3)pthread_cond_wait函数
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
作用:阻塞等待条件变量cond(形参1)满足条件,且释放已经掌握的互斥锁(解锁互斥量)相当于pthread_mutex_unlock(&mutex)(注意这是一个原子操作,即阻塞等待的同时马上解锁,类似sigsuspend函数);当被唤醒(signal或broadcast函数),pthread_cond_wait函数返回,解除阻塞并重新申请获取互斥锁:pthread_mutex_lock(&mutex);
(4)pthread_cond_timedwait函数
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
作用:与pthread_cond_wait函数作用相同,但其限时等待一个条件变量,即如果在规定的时间点(第三个形参)还未被唤醒时,该线程自动唤醒并解除阻塞重新申请获取互斥锁:pthread_mutex_lock(&mutex);
参数3:struct timespec结构体。
struct timespec {
time_t tv_sec; /* seconds */ 秒
long tv_nsec; /* nanosecondes*/ 纳秒
}
struct timespec结构体定义的是绝对时间(从1970年1月1日00:00:00开始计时的时间,unix操作系统的诞辰是1969年末)。time(NULL)返回的就是绝对时间(秒)。而alarm(1)是相对时间(相对于当前),相对当前时间定时1秒钟。
struct timespec t = {1, 0}; pthread_cond_timedwait (&cond, &mutex, &t); 只能定时到 1970年1月1日 00:00:01秒(早已经过去)。 1970年1月1日 00:00:00秒作为计时元年。正确用法:
time_t cur = time(NULL); //获取当前时间(绝对时间)
struct timespec t; //定义timespec 结构体变量t
t.tv_sec = cur+1; //定时1秒
pthread_cond_timedwait (&cond, &mutex, &t); 传参 参考APUE.11.6线程同步条件变量小节
在讲解setitimer函数时我们还提到另外一种时间类型:
struct timeval {
time_t tv_sec; /* seconds */ 秒
suseconds_t tv_usec; /* microseconds */ 微秒
};
(5)pthread_cond_signal函数
int pthread_cond_signal(pthread_cond_t *cond);
作用:唤醒至少一个阻塞在条件变量上的线程。
(6)pthread_cond_broadcast函数
int pthread_cond_broadcast(pthread_cond_t *cond);
作用:唤醒全部阻塞在条件变量上的线程
(7)生产者消费者条件变量模型
线程同步典型的案例即为生产者消费者模型,而借助条件变量来实现这一模型,是比较常见的一种方法。假定有两个线程,一个模拟生产者行为,一个模拟消费者行为。两个线程同时操作一个共享资源(一般称之为汇聚),生产向其中添加产品,消费者从中消费掉产品。
看如下示例,使用条件变量模拟生产者、消费者问题:
//生产者消费者条件变量模型
#include
#include
#include
#include
#include
struct production {
int num;
struct production *next;
};
struct production *head = NULL; //定义全局指针head
struct production *rer = NULL; //定义全局指针rer
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //静态初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //静态初始化
void *productor( void *arg ) //生产者
{
srand( time( NULL ) );
while(1){
pthread_mutex_lock( &mutex );
rer = (struct production *)malloc( sizeof(struct production) );
rer->num = (rand( )%400 + 1);
rer->next = head;
head = rer;
printf("--------The production is %d.\n",rer->num);
pthread_mutex_unlock( &mutex );
pthread_cond_signal( &cond ); //唤醒因wait阻塞的线程
sleep( rand( )%3 );
}
return NULL;
}
void *consumer( void *arg ) //消费者
{
srand( time( NULL ) );
while(1){
pthread_mutex_lock( &mutex );
while( head == NULL ) //注意不能是if,必须采用循环
pthread_cond_wait( &cond, &mutex );
rer = head;
head = rer->next;
printf("++++++++The consumer is %d.\n",rer->num);
pthread_mutex_unlock( &mutex );
sleep( rand( )%3 );
}
return NULL;
}
int main( void )
{
pthread_t pid, cid;
int ret;
ret = pthread_create( &pid, NULL, productor, NULL);
if( ret != 0)
{
fprintf(stderr,"pthread_create error1: %s\n",strerror(ret));
exit(1);
}
ret = pthread_create( &cid, NULL, consumer, NULL);
if( ret != 0)
{
fprintf(stderr,"pthread_create error2: %s\n",strerror(ret));
exit(1);
}
ret = pthread_join(pid,NULL);
if( ret != 0)
{
fprintf(stderr,"pthread_join error1: %s\n",strerror(ret));
exit(1);
}
ret = pthread_join(cid,NULL);
if( ret != 0)
{
fprintf(stderr,"pthread_join error2: %s\n",strerror(ret));
exit(1);
}
pthread_cond_destroy(&cond); //销毁条件变量
pthread_mutex_destroy(&mutex); //销毁互斥锁
return 0;
}
[root@localhost 02_pthread_sync_test]# ./pthrd_cond
--------The production is 257.
++++++++The consumer is 257.
--------The production is 324.
--------The production is 327.
++++++++The consumer is 327.
--------The production is 180.
--------The production is 313.
++++++++The consumer is 313.
--------The production is 285.
++++++++The consumer is 285.
++++++++The consumer is 180.
++++++++The consumer is 324.
--------The production is 21.
--------The production is 351.
++++++++The consumer is 351.
分析: