RT-Thread-08-生产者消费者问题

该文详细介绍了生产者消费者问题的解决思路,包括线程间的互斥与同步。生产者在缓存区满时不写数据,消费者在缓存区空时不读取数据。通过使用信号量来管理共享资源——一个固定大小的缓存区,确保了生产者和消费者的正确协作。文中给出了使用RT-Thread实时操作系统实现的示例代码,展示了如何创建和使用信号量来控制生产者线程和消费者线程的执行。
摘要由CSDN通过智能技术生成

生产者消费者问题

生产者和消费者的问题实际上是要解决线程间互斥和同步的问题;
两个线程,一个生产者线程,一个消费者线程。两个线程共享一个初始为空、固定大小为n的缓存区;
生产者,生产一段数据,只有缓冲区没满时,生产者才能把消息放入到缓冲区,否则必须等待,如此反复;
消费者,从缓存区中一次只读取一段数据,只有缓冲区非空时才可读取,否则必须等待,如此反复;
核心问题
1、保证生产者在缓存区满的时候不向缓存区写数据;
2、不让消费者在缓存区为空的时候读取数据;
互斥访问的问题:缓冲区是临界资源,它一个时刻只允许一个生产者写入信息,或者只允许一个消费者从中读取信息;
同步的问题:生产者和消费者是相互协作的关系,只有在生产者生产之后,消费者才能消费;

互斥模型:
在这里插入图片描述
同步模型:
在这里插入图片描述
生产者,循环中,每次生产数据时,先获取缓存区信号量是否为空,这里给的初值5,初始时为5个空位;然后获取缓存区读写信号量,初值为1,可获取。对缓存区操作后,释放缓存区读写信号量;再释放缓存区满信号量(供消费者能够读取数据判断)。
消费者,循环中,每次读取数据时,先获取缓存区满的信号量,然后获取缓存区读写信号量,然后再进行读数据操作,之后释放缓存区读写信号量,最后释放缓存区空信号量;
官方示例代码:

/* 
 * Copyright (c) 2006-2018, RT-Thread Development Team 
 * 
 * SPDX-License-Identifier: Apache-2.0 
 * 
 * Change Logs: 
 * Date           Author       Notes 
 * 2018-08-24     yangjie      the first version 
 */  

/*
 * 程序清单:生产者消费者例子
 *
 * 这个例子中将创建两个线程用于实现生产者消费者问题
 *(1)生产者线程将cnt值每次加1并循环存入array数组的5个成员内;
 *(2)消费者线程将生产者中生产的数值打印出来,并累加求和
 */
#include <rtthread.h>

#define THREAD_PRIORITY       6
#define THREAD_STACK_SIZE     512
#define THREAD_TIMESLICE      5

/* 定义最大5个元素能够被产生 */
#define MAXSEM 5

/* 用于放置生产的整数数组 */
rt_uint32_t array[MAXSEM];

/* 指向生产者、消费者在array数组中的读写位置 */
static rt_uint32_t set, get;

/* 指向线程控制块的指针 */
static rt_thread_t producer_tid = RT_NULL;
static rt_thread_t consumer_tid = RT_NULL;

struct rt_semaphore sem_lock;
struct rt_semaphore sem_empty, sem_full;

/* 生产者线程入口 */
void producer_thread_entry(void *parameter)
{
    int cnt = 0;

    /* 运行10次 */
    while (cnt < 10)
    {
        /* 获取一个空位 */
        rt_sem_take(&sem_empty, RT_WAITING_FOREVER);

        /* 修改array内容,上锁 */
        rt_sem_take(&sem_lock, RT_WAITING_FOREVER);
        array[set % MAXSEM] = cnt + 1;
        rt_kprintf("the producer generates a number: %d\n", array[set % MAXSEM]);
        set++;
        rt_sem_release(&sem_lock);

        /* 发布一个满位 */
        rt_sem_release(&sem_full);
        cnt++;

        /* 暂停一段时间 */
        rt_thread_mdelay(20);
    }

    rt_kprintf("the producer exit!\n");
}

/* 消费者线程入口 */
void consumer_thread_entry(void *parameter)
{
    rt_uint32_t sum = 0;

    while (1)
    {
        /* 获取一个满位 */
        rt_sem_take(&sem_full, RT_WAITING_FOREVER);

        /* 临界区,上锁进行操作 */
        rt_sem_take(&sem_lock, RT_WAITING_FOREVER);
        sum += array[get % MAXSEM];
        rt_kprintf("the consumer[%d] get a number: %d\n", (get % MAXSEM), array[get % MAXSEM]);
        get++;
        rt_sem_release(&sem_lock);

        /* 释放一个空位 */
        rt_sem_release(&sem_empty);

        /* 生产者生产到10个数目,停止,消费者线程相应停止 */
        if (get == 10) break;

        /* 暂停一小会时间 */
        rt_thread_mdelay(50);
    }

    rt_kprintf("the consumer sum is: %d\n", sum);
    rt_kprintf("the consumer exit!\n");
}

int producer_consumer(void)
{
    set = 0;
    get = 0;

    /* 初始化3个信号量 */
    rt_sem_init(&sem_lock, "lock",     1,      RT_IPC_FLAG_FIFO);
    rt_sem_init(&sem_empty, "empty",   MAXSEM, RT_IPC_FLAG_FIFO);
    rt_sem_init(&sem_full, "full",     0,      RT_IPC_FLAG_FIFO);

    /* 创建生产者线程 */
    producer_tid = rt_thread_create("producer",
                                    producer_thread_entry, RT_NULL,
                                    THREAD_STACK_SIZE,
                                    THREAD_PRIORITY - 1, THREAD_TIMESLICE);
    if (producer_tid != RT_NULL)
    {
        rt_thread_startup(producer_tid);
    }
    else
    {
        rt_kprintf("create thread producer failed");
        return -1;
    }

    /* 创建消费者线程 */
    consumer_tid = rt_thread_create("consumer",
                                    consumer_thread_entry, RT_NULL,
                                    THREAD_STACK_SIZE,
                                    THREAD_PRIORITY + 1, THREAD_TIMESLICE);
    if (consumer_tid != RT_NULL)
    {
        rt_thread_startup(consumer_tid);
    }
    else
    {
        rt_kprintf("create thread consumer failed");
        return -1;
    }

    return 0;
}

/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(producer_consumer, producer_consumer sample);

运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值