在《线程同步—互斥锁》一文中,我们分析了只用互斥锁同步线程的弊端——CPU的效率和时效性不可兼得。下面,我们通过使用条件变量,在保证CPU效率的前提下,提高程序的时效性。
只用互斥锁同步线程,其CPU占用率之所以高,是因为线程需要轮询,即需要不停的检查条件是否满足。我们使用条件变量,当条件不满足时,使线程阻塞。一旦条件满足,就会解除阻塞,继续往下执行。这样,线程就不需要轮询了,因此不需要占用太多CPU资源,而且具有很高的及时性。
当条件满足时,可以唤醒单个阻塞的线程,也可以唤醒多个线程。注释掉的代码段,是唤醒多个线程的。代码如下:
#include
#include
char buffer[128];
int buffer_has_data=0;
pthread_mutex_t mutex;//锁定标志
pthread_cond_t cond;//唤醒条件变量
void write_buffer(char *data)
{
pthread_mutex_lock(&mutex);//锁定
if(buffer_has_data==0)
{
sprintf(buffer,"%s",data);
buffer_has_data=1;
pthread_cond_signal(&cond);//当有数据可读时,唤醒单个线程
// pthread_cond_broadcast(&cond);//唤醒所有线程,test1,test2
}
pthread_mutex_unlock(&mutex);//解锁
}
void read_buffer(void)
{
while(1)
{
pthread_mutex_lock(&mutex);//锁定, 阻塞前被锁上
/*无数据时,一般用循环体阻塞。*/
while(!buffer_has_data)
{
/*如果不满足被唤醒的条件,则释放互斥锁,阻塞在此处;
当唤醒的条件满足时,重新加锁,并解除阻塞。*/
pthread_cond_wait(&cond,&mutex);
}
printf("read buffer,data = %s\n",buffer);
buffer_has_data=0;
pthread_mutex_unlock(&mutex);//解锁
}
}
/*
void test1()
{
while(1)
{
pthread_cond_wait(&cond,&mutex);//阻塞线程,等待唤醒
printf("test1 run\n");
}
}
void test2()
{
while(1)
{
pthread_cond_wait(&cond,&mutex);//阻塞线程,等待唤醒
printf("test2 run\n\n");
}
}
*/
int main(int argc,char **argv)
{
char input[128];
pthread_t reader,t1,t2;
pthread_mutex_init(&mutex,NULL);//生成互斥锁mutex,默认属性初始化
pthread_cond_init(&cond,NULL);//生成一个唤醒变量,默认属性:同一进程内的所有线程使用.和外部的进程没有瓜葛,进程外部不可用
pthread_create(&reader,NULL,(void*)(read_buffer),NULL);
// pthread_create(&t1,NULL,(void*)(test1),NULL);//测试一次唤醒多个线程
// pthread_create(&t2,NULL,(void*)(test2),NULL);//测试一次唤醒多个线程
while(1)
{
scanf("%s",input);
write_buffer(input);
}
pthread_join(reader,NULL);//等待线程退出
pthread_join(t1,NULL);
pthread_join(t2,NULL);
pthread_cond_destroy(&cond);//释放阻塞唤醒变量
pthread_mutex_destroy(&mutex);//释放互斥锁mutex资源
return 0;
}