条件变量
条件变量是另一种逻辑稍微复杂一点点的同步互斥机制,他必须跟互斥锁一起配合使
用,他的应用场景也是非常常见的,先来看一个例子:小楠是一名在校学生,每个月都会从父母那里得到一笔生活费。现在她的钱花光了,想要去取钱。但是很显然取钱这样的事情不是想干就能干的,前提是卡里必须得有钱才行!于是小楠拿起手机一查发现:余额为¥ 0 。现在她除了干瞪眼,唯一能干的事情也许只有一件:等。等到她爸妈汇了钱打电话通知她为止。但更进一步,即便是她爸妈汇了钱也打了电话通知了她,此刻她也不能一定保证能取到钱,因为与此同时她的众多兄弟姐妹(统统共用一个银行账号)很可能已经抢先一步将钱悉数取光了!因此当小楠收到爸妈的电话之后,需要再次确认是否有钱,才能取钱。
上图中,线程一旦发现余额为 0,就会进入等待睡眠,与此同时必须先释放互斥锁,如
果带着锁去睡大觉,那么结果是谁也别想修改余额,大家都进入无限期的阻塞之中,相反从等待队列中出来的时候必须先持有互斥锁,因为出来后又要马上访问余额这个共享资源的。特别注意的是,有两把锁头是在框框里面的,这表示当一条线程进入某个条件变量的等待队列中等待,以及从该等待队列中出来时,分别对互斥锁的解锁和加锁都是自动完成的,这是为什么说条件变量跟互斥锁是配套使用的原因。
#include<stdio.h>
#include <semaphore.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
pthread_cond_t cond;
pthread_mutex_t lock;
int num=0;
void *function(void *arg)
{
char *msg=(char *)arg;
while (1)
{
if (num<100)
{
pthread_mutex_lock(&lock);
printf("%s添加互斥锁成功!准备取钱\n",msg);
//如果金额不足,则会进入条件变量的队列中等待
//进入之前该函数会帮我们把lock互斥锁解开,以便存钱
pthread_cond_wait(&cond, &lock);
}
num-=100;
printf("我是%s号线程,目前余额%d\n",msg,num);
pthread_mutex_unlock(&lock);
sleep(10);
}
}
int main(int argc, char const *argv[])
{
//初始化条件变量
pthread_cond_init(&cond, NULL);
//初始化互斥锁
pthread_mutex_init(&lock,NULL);
pthread_t thread1;
pthread_t thread2;
pthread_t thread3;
pthread_t thread4;
pthread_create(&thread1, NULL,function, "1");
pthread_create(&thread2, NULL,function, "2");
pthread_create(&thread3, NULL,function, "3");
pthread_create(&thread4, NULL,function, "4");
while (1)
{
//作为父母,时刻关注账号中的金钱
if(num<100)
{
printf("余额不足,准备转帐!\n");
pthread_mutex_lock(&lock);
printf("main添加互斥锁成功!\n");
//如果小于100,自觉存钱
num+=100;
printf("微信转账100块\n");
pthread_mutex_unlock(&lock);
pthread_cond_signal(&cond);
printf("成功唤醒所有孩子!\n");
printf("解锁.....\n");
sleep(1);
}
}
return 0;
}