多线程中经典的生产消费者模型

买票问题

这是一个在多线程中必遇到的问题, 多个线程抢一张票, 如果不加限制会出现买票 卖出负票或者
多个线程买重票的问题

所以线程在访问临界资源时应该上锁

出现负票的原因

线程 1 2 同时 1票
线程二 取 1票 ->判断1票可以 -> 保存上下文 切换->
线程1 执行完 1 - 1写回内存 票 0

切到线程二 (由上下文得知 已经进行过判断 直接运算) 0 -1 = -1 写回内存 票 -1

这里写图片描述

pthread下的互斥锁

//创建一个锁
pthread_mutex_t  mutex;
//锁还可以一次性用宏初始化(静态初始化)
mutex = PTHREAD_MUTEX_INITIALIZER
//将锁初始化(动态初始化)
pthread_mutex_init(&mutex, NULL);
//上锁
pthread_mutex_lock(&mutex);
//放锁
pthread_mutex_unlock(&mutex);
//锁用完销毁锁
pthread_mutex_destory(&mutex, NULL);

加锁版本的买票系统

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int tickets = 1000;

void* sell_tickets(void* arg)
{
    while(1)
    {
        pthread_mutex_lock(&mutex);
        if(tickets <=  0)
        {
            printf("sell out\n");
            pthread_mutex_unlock(&mutex);
            return;
        }
        char* id = (char*) arg;
        usleep(1000);
        tickets--;
        printf("%s sells one ticket ,left %d ticket\n", id, tickets);
        pthread_mutex_unlock(&mutex);
    }
}

int main()
{
    pthread_t thread1,thread2, thread3;
    pthread_create(&thread1, NULL, sell_tickets, "thread1");
    pthread_create(&thread2, NULL, sell_tickets, "thread2");
    pthread_create(&thread3, NULL, sell_tickets, "thread3");
    pthread_join(thread1,NULL);
    pthread_join(thread2,NULL);
    pthread_join(thread3,NULL);
    return 0;
}

生产消费者模型

这里写图片描述

分析问题

消费者和消费者之前是互斥的, 那么就需要在众多消费者中设置一把互斥锁

生产者和生产者之间也是互斥的.那么就需要在众多生产者中设置一把一把互斥锁

到这里就 实现了生产者和消费者的互斥, 还剩下一个问题是要解决生产消费者之间的同步问题

当生产者生产一个产品后,就要通知消费者来取产品,

当消费者消费一个产品后,就要通知生产者去生产产品

我们发现,通知这个动作就是 发信号,这就用到了线程中的条件变量

条件变量函数接口

1. 初始化条件变量
宏常量静态初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
函数动态初始化
 #include <pthread.h>
 int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
2.等待和通知条件变量
#include <pthread.h>
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);

四个函数分别是
等待函数: 时间内等待,普通等待,
唤醒函数: 广播唤醒,单点唤醒
至于为什么条件变量后面要将锁作为参数传入,详见:多线程中 关于条件变量和互斥锁的疑惑

3.销毁条件变量
 #include <pthread.h>
 int pthread_cond_destroy(pthread_cond_t *cond);

至此我们分析出要保证生产消费者正常的完成同步与互斥,所需要的条件是

1.两个锁(分别是消费者,生产者)
2 条件变量(生产者通知消费者消费产品,消费者通知生产者生产产品)


测试代码

https://github.com/WayKwin/WD_backup/blob/master/WD/OS/Thread/p_c_model.c

测试结果

这里写图片描述

基于环形队列的消费生产者模型

和之前的生产消费者模型一样,只是条件等待条件的改变, 消费者和生产这都不能越界
例如队列满了,生产者必须等消费者
消息队列为空,消费者必须等待生产者
这里写图片描述

嘿嘿 ,win10 的paint3D还是很好玩的….

代码

https://github.com/WayKwin/WD_backup/blob/master/WD/OS/Thread/sem.c

测试

这里写图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值