[Linux] 食客吃面模型(条件变量实现同步)

version 1.0

一个顾客,一个老板,各为一个线程。

/*************************************************************************
*> version : 1.0
*> Author: giturtle
*> Describe: 实现条件变量的基本使用
    吃面的前提是:有人做面
    
    如果没有现成的面,等待老板做出来
    老板做出来面,就要唤醒顾客

    老板不会做太多的面,只会提前做一碗面
    如果已经有面做出来,但是没人吃,不会再做第二碗,进行等待
    顾客吃碗面之后,要求再来一碗,进行唤醒(老板)
*************************************************************************/
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>

int have_noodle = 1;

pthread_cond_t cond;
pthread_mutex_t mutex;
void *thr_boss(void * arg) {
    while(1) {
		pthread_mutex_lock(&mutex);		
		//若面没有卖出去,则等待
		if (have_noodle == 1) {
			pthread_cond_wait(&cond, &mutex);	//等待(死等)
		    //pthread_cond_wait 中集合了解锁后挂起的操作(原子操作)
		    //有可能还没来得及挂起就已经有人唤醒--白唤醒--导致死等
		}
		//面被人吃了,要再做一碗
		printf("boss:produce an noodle +1\n");
		have_noodle += 1;
		//此时面做出来了~端走端走(唤醒顾客)
		pthread_cond_signal(&cond);
		pthread_mutex_unlock(&mutex);
    }
    return NULL;
}
void *thr_customer(void *arg) {
    while(1) {
		pthread_mutex_lock(&mutex);
		//若此时没有现成的面,就等老板做好
		if (have_noodle == 0) {
		    pthread_cond_wait(&cond, &mutex);	//等待
		}
		//如果有面了就可以吃面了
		printf("customer:delicious~ noodle -1\n");
		have_noodle -= 1;
		//吃完没有吃饱~ 再来一碗 (唤醒老板)
		pthread_mutex_unlock(&mutex);
		pthread_cond_signal(&cond);
	}
    return NULL;
}

int main(int argc, char *argv[]){
    pthread_t tid1, tid2;
    int ret;
    
    //条件变量 初始化
    pthread_cond_init(&cond, NULL);	//或 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
    pthread_mutex_init(&mutex, NULL);
    ret = pthread_create(&tid1, NULL, thr_boss, NULL);
    if (ret != 0) {
		printf("boss create error\n");
		return -1;
    }
    ret = pthread_create(&tid2, NULL, thr_customer, NULL);
    if (ret != 0) {
		printf("customer create error\n");
		return -1;
    }
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    
    //销毁条件变量
    pthread_cond_destroy(&cond);
    pthread_mutex_destroy(&mutex);
    return 0;
}

运行结果

boss:produce an noodle +1
customer:delicious~ noodle -1
boss:produce an noodle +1
customer:delicious~ noodle -1
boss:produce an noodle +1
customer:delicious~ noodle -1
boss:produce an noodle +1
customer:delicious~ noodle -1
boss:produce an noodle +1
customer:delicious~ noodle -1
boss:produce an noodle +1
customer:delicious~ noodle -1
boss:produce an noodle +1
customer:delicious~ noodle -1
boss:produce an noodle +1
customer:delicious~ noodle -1
boss:produce an noodle +1
customer:delicious~ noodle -1
boss:produce an noodle +1
customer:delicious~ noodle -1

version 2.0

多个厨师,多个食客。

  • 因为有可能多个线程(食客)等待在条件变量上,其中一个完成吃面动作解锁,此时第二个正好获取到锁资源,进行吃面操作,造成一碗面被多人进食的错误情景。
    所以:将回调函数中的if判定条件改为while循环判定,进行吃面操作之前先判断是否还有面。

  • pthread_cond_wait()唤醒的是所有等待在条件变量上的线程,但有可能被唤醒的这个线程也是一个做面的线程,因为已经有面,条件不满足而陷入等待,导致死等。
    所以:线程有多少角色,就应该有多少个条件变量。分别等待,分别唤醒。

/*************************************************************************
*> version : 2.0
*> Author: giturtle
*> Describe: 处理一碗面被多人食用的情况
*************************************************************************/
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>

int have_noodle = 1;
pthread_cond_t boss;
pthread_cond_t customer;
pthread_mutex_t mutex;
void *thr_boss(void * arg) {
    while(1) {		//循环判断,有可能第一个吃面者已经改为 0 了
		pthread_mutex_lock(&mutex);
		//若面没有卖出去,则等待
		while(have_noodle == 1) {
		    pthread_cond_wait(&boss, &mutex);
		    //1. 解锁  -》 2. 休眠   -》   3. 被唤醒后加锁
		}
		//面被人买了,要再做一碗
		printf("boss:produce an noodle +1\n");
		have_noodle += 1;
		pthread_cond_signal(&customer);
		pthread_mutex_unlock(&mutex);
    }
    return NULL;
}
void *thr_customer(void *arg) {
    while(1) {
		pthread_mutex_lock(&mutex);
		//若没有现成的面,等老板做好
		while(have_noodle == 0) {
		    pthread_cond_wait(&customer, &mutex);
		}
		printf("customer:delicious~ noodle -1");
		have_noodle -= 1;
		
		pthread_mutex_unlock(&mutex);
		pthread_cond_signal(&boss);
    }
    return NULL;
}

int main(int argc, char *argv[]){
    pthread_t tid1, tid2;
    int ret;

    pthread_cond_init(&boss, NULL);
    pthread_cond_init(&customer, NULL);
    pthread_mutex_init(&mutex, NULL);
    int i = 0;
    for (i = 0; i < 2; i++) {
		ret = pthread_create(&tid1, NULL, thr_boss, NULL);
		if (ret != 0) {
		    printf("boss error\n");
		    return -1;
		}
    }
    for (i = 0; i < 2; i++) {
		ret = pthread_create(&tid2, NULL, thr_customer, NULL);
		if (ret != 0) {
		    printf("customer error\n");
		    return -1;
		}
    }
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    //销毁条件变量
    pthread_cond_destroy(&boss);
    pthread_cond_destroy(&customer);
    pthread_mutex_destroy(&mutex);
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

giturtle

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值