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。