条件变量用于等待线程而不是加锁,条件变量通常与互斥量一起使用。条件变量之所以和互斥量一起使用,主要是因为互斥量一个明显的特点就是只有锁定和解锁两种状态,而条件变量可以通过让线程阻塞等待另一个线程发送信号来使用弥补了互斥锁的不足,所以互斥锁和条件变量通常一起使用。当条件满足时,线程通常会解锁并等待条件改变。一旦另一个线程修改了环境变量,它会通知相应的环境变量唤醒一个或多个被条件变量阻塞的线程。这些被唤醒的线程会重新获取锁并测试是否满足条件。通常条件变量用于线程之间的同步;允许其中一个执行流在不满足条件时暂停并等待。总之,条件变量本身不是锁,但它也会造成线程阻塞,通常与互斥锁一起使用,为多线程提供会面场所。条件变量的优点:与mutex相比,条件变量可以减少竞争。如果只是一个互斥锁,那么无论共享资源中是否有数据,生产者和所有消费者都会争先恐后地去抢锁,造成资源浪费。如果直接使用mutex,除了生产者和消费者之间的竞争,消费者还需要竞争mutex,但是如果聚合(链表)中没有数据,消费者之间竞争mutex是没有意义的。有了条件变量机制,只有当生产者完成生产时,才会引起消费者之间的竞争。提高了程序效率。主要应用函数:pthread_cond_init函数、pthread_cond_destroy函数、pthread_cond_wait函数、pthread_cond_timedwait函数、pthread_cond_signal函数、pthread_cond_broadcast函数。以上六个函数的返回值分别是:成功返回0,失败直接返回一个错误号。pthread_cond_t类型:用于定义条件变量,如:pthread_cond_tcond;pthread_cond_init函数函数原型:intpthread_cond_init(pthread_cond_trestrictcond,constpthread_condattr_trestrictattr);function函数:初始化一个条件变量参数说明:cond:条件变量,应该调用将&cond传给函数attr:条件变量属性,一般传NULL,即默认属性也可以用来初始化条件变量:pthread_cond_t条件=PTHREAD_COND_INITIALIZER;pthread_cond_destroy函数函数原型:intpthread_cond_destroy(pthread_cond_t*cond);function功能:销毁一个条件变量pthread_cond_wait函数函数原型:intpthread_cond_wait(pthread_cond_trestrictcond,pthread_mutex_trestrictmutex);函数功能:块等待条件变量。具体来说,它有以下三个功能:阻塞等待条件变量cond(参考文献1)被满足;释放已经掌握的互斥量mutex(解锁互斥量)相当于pthread_mutex_unlock(&mutex);唤醒后,pthread_cond_wait函数返回,Unblock并重新申请获取互斥量。步骤1和2是一个原子操作。pthread_cond_timedwait函数函数原型:intpthread_cond_timedwait(pthread_cond_trestrictcond,pthread_mutex_trestrictmutex,conststructtimespec*restrictabstime);功能:在限定时间内等待一个条件变量参数说明:前两个比较容易理解,重点关注第三个参数。这里是一个structtimespec结构体,可以在mansem_timedwait中查看。结构体原型如下:structtimespec{time_ttv_sec;/seconds/secondslongtv_nsec;/nanosecondes/nanoseconds}structtimespec定义的形参abstime是一个绝对时间。注意是绝对时间,不是相对时间。什么是绝对时间?2018年10月1日10:10:00,这是一个绝对时间。什么是相对时间?洗衣机定时30分钟洗衣服是一个相对时间,也就是说从当前时间算起30分钟,以此类推。例如:time(NULL)返回绝对时间。而alarm(1)是一个相对时间,设置为相对于当前时间1秒。adstime的相对时间是相对于1970年1月1日的00:00:00,也就是UNIX计时元年。这是一个错误的用法:structtimespect={1,0};pthread_cond_timedwait(&cond,&mutex,&t);两者都还没有出生。正确用法:time_tcur=time(NULL);获取当前时间。结构timespect;定义timespec结构变量tt.tv_sec=cur+1;时间1秒pthread_cond_timedwait(&cond,&mutex,&t);传参pthread_cond_signal函数函数原型:intpthread_cond_signal(pthread_cond_t*cond);函数功能:唤醒至少一个阻塞在条件变量上的线程pthread_cond_broadcast函数函数原型:intpthread_cond_broadcast(pthread_cond_t*cond);功能:唤醒阻塞在条件变量生产者消费者条件变量模型上的所有线程无论什么语言,只要提到线程同步,一个典型的案例就是生产者消费者模型。在Linux环境下,借助条件变量来实现这个模型是一种比较常见的方法。假设有两个线程,一个模拟生产者行为,一个模拟消费者行为。两个线程在共享资源(通常称为池)上同时运行,生产者从中添加产品,消费者从中消费产品。请参见以下示例,使用条件变量来模拟生产者和消费者问题:下一个;intnum;}msg_t;msg_t*head=NULL;msg_t*mp=NULL;/*条件变量和互斥锁的静态初始化*/pthread_cond_thas_product=PTHREAD_COND_INITIALIZER;pthread_mutex_tmutex=PTHREAD_MUTEX_INITIALIZER;void*th_producer(void*arg){while(1){mp=malloc(sizeof(msg_t));mp->num=rand()%1000;//模拟生产一个产品printf("---produce:%d--------\n",mp->num);pthread_mutex_lock(&mutex);mp->下一个=头;头=mp;pthread_mutex_unlock(&mutex);pthread_cond_signal(&has_product);//唤醒线程消费产品sleep(rand()%5);}returnNULL;}void*th_consumer(void*arg){while(1){pthread_mutex_lock(&mutex);while(head==NULL){//如果链表中没有product,就没有抢锁的必要,一直阻塞等待pthread_cond_wait(&has_pr产品,&mutex);}mp=头;head=mp->下一个;//模拟消费一个产品pthread_mutex_unlock(&mutex);printf("=========消耗:%d======\n",mp->num);免费(国会议员);mp=NULL;睡眠(兰德()%5);}returnNULL;}intmain(){pthread_tpid,cid;srand(时间(NULL));pthread_create(&pid,NULL,th_producer,NULL);pthread_create(&cid,NULL,th_consumer,NULL);pthread_join(pid,NULL);pthread_join(cid,NULL);敬请关注公众号良旭Linux,在公众号回复1024免费获得5T技术资料,包括:Linux、C/C++、Python、树莓派、嵌入式、Java、人工智能等。公众号回复进群,邀您加入专家云技术交流群。最后,最近有很多朋友找我要一份Linux学习路线图,所以我结合自己的经验,利用业余时间熬夜一个月,整理了一本电子书。无论你是面试还是自我提升,相信都会对你有所帮助!免费送给大家,只求大家给我点个赞!电子书|LinuxDevelopmentLearningRoadmap也希望有小伙伴可以加入我的行列,把这本电子书做得更加完美!获得?希望老铁们来个三连击,让更多人看到这篇文章。推荐阅读:干货|程序员和高级架构师免费发送工件的必备资源|支持搜索的资源网站
