Linux多线程编程(二)
引言
条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待条件变量的条件成立而挂起(此时不再占用cpu);另一个线程使条件成立(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。
函数原型
1.定义条件变量
#include<pthread.h> /*定义两个条件变量*/ pthread_cond_tcond_pro,cond_con;
2.初始化和销毁条件变量
#include<pthread.h> intpthread_cond_init(pthread_cond_t*restrictcond,constpthread_condattr_t*restrictattr);intpthread_cond_destroy(pthread_cond_t*cond);/*初始化条件变量*/ pthread_cond_init(&cond_pro,NULL); pthread_cond_init(&cond_con,NULL); /*销毁条件变量*/ pthread_cond_destroy(&cond_pro); pthread_cond_destroy(&cond_pro);
3.等待和激发条件
#include<pthread.h> intpthread_cond_wait(pthread_cond_t*restrictcond,pthread_mutex_t*restrictmutex); intpthread_cond_broadcast(pthread_cond_t*cond); intpthread_cond_signal(pthread_cond_t*cond); /*等待条件*/ /*注意:pthread_cond_wait为阻塞函数。解开锁,再等待。等条件满足时,需要抢到锁,才可以被唤醒*/ pthread_cond_wait(&cond_pro,&mutex); /*激发条件*/ /*所有因为不满足条件的线程都会阻塞在条件变量cond_pro中的一个队列中*/ /*以广播方式,通知所有被阻塞的所有线程*/ pthread_cond_broadcast(&cond_pro); /*以signal方式,只通知排在最前面的线程*/ pthread_cond_signal(&cond_pro);
代码
/************************************************************************* >FileName:my_con.c >Author:KrisChou >Mail:zhoujx0219@163.com >CreatedTime:Tue26Aug201410:24:29AMCST ************************************************************************/ #include<stdio.h> #include<stdlib.h> #include<string.h> #include<pthread.h> #include<unistd.h> #defineCELL10 #defineFLORE0 inti=0;/*所有线程共享的全局变量,此处假定至多递增至10,最小减到0*/ pthread_mutex_tmutex;/*定义互斥锁*/ pthread_cond_tcond_pro,cond_con;/*定义两个条件变量*/ /*生产者线程*/ void*pro_handler(void*arg) { pthread_detach(pthread_self());/*由系统回收线程资源,而非主线程回收资源,此类情况主线程是个服务器,永久不会退出*/ while(1) { pthread_mutex_lock(&mutex); while(i>=CELL) { pthread_cond_wait(&cond_pro,&mutex); /*continue是轮询,此处是阻塞*/ /*把锁放开再等,第一个参数是结构体指针,其中有成员存放被阻塞的函数*/ /*不占cpu*/ /*不满足条件时才会等,需要别人告诉它,才能唤醒它*//*当它返回时,锁也要回来了*/ } i++; if(i==1) { /*由空到不空,唤醒消费者*/ pthread_cond_signal(&cond_con);/*不会立马signal被阻塞的消费者线程,因为其还要等锁抢回来*/ } printf("addi:%d\n",i); pthread_mutex_unlock(&mutex); sleep(rand()%5+1); } } /*消费者线程*/ void*con_handler(void*arg) { pthread_detach(pthread_self()); while(1) { pthread_mutex_lock(&mutex); while(i<=FLORE) { pthread_cond_wait(&cond_cno,&mutex); } i--; if(i==9)/*由满到不满,要告诉生产者,以便将其唤醒*//*此处,直接signal也可以,我们是为了更加精确*/ { pthread_cond_signal(&cond_pro); } printf("coni:%d\n",i); pthread_mutex_unlock(&mutex); sleep(rand()%5+1); } } intmain(intargc,char*argv[])//exe+num-num { srand(getpid()); intcon_cnt,pro_cnt; pro_cnt=atoi(argv[1]); con_cnt=atoi(argv[2]); pthread_mutex_init(&mutex,NULL); pthread_cond_init(&cond_pro,NULL); pthread_cond_init(&cond_con,NULL); pthread_t*arr=(pthread_t*)calloc(con_cnt+pro_cnt,sizeof(pthread_t)); intindex=0; while(pro_cnt>0) { pthread_create(arr+index,NULL,pro_handler,NULL); index++; pro_cnt--; } while(con_cnt>0) { pthread_create(arr+index,NULL,con_handler,NULL); index++; con_cnt--; } while(1); pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cond_pro); pthread_cond_destroy(&cond_con); return0; }
注意
无论是在生产者线程,还是在消费者线程中。标记黄色部分的判断条件必须用while。以生产者线程举例,当i>=CELL时,也就是i满时,此时执行pthread_cond_wait(&cond_cno,&mutex);该生产者线程被挂起。必须等到消费者线程pthread_cond_signal(&cond_pro);将其唤醒。但是消费者将其signal还不够,被挂其的生产者线程必须重新拿到锁,才可以被激活。但是,由于在消费者signal的同时,生产者并不能立即抢到锁,所以此时可能i值又改变变为大于等于10了。因此必须用while。不然可能导致i>10。