8.IPC之消费者生产者问题//依据RT-Thread内核编程的学习记录(非内核实现)

/*
 * 程序清单:生产者消费者例子
 *
 * 这个例子中将创建两个线程用于实现生产者消费者问题
 *(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;
static rt_mutex_t dynamic_mutex = RT_NULL;

/* 生产者线程入口 */
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);
				rt_mutex_take(dynamic_mutex , 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_mutex_release(dynamic_mutex);

        /* 发布一个满位 */
        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);
				rt_mutex_take(dynamic_mutex, 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_mutex_release(dynamic_mutex);

        /* 释放一个空位 */
        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);
		
		dynamic_mutex = rt_mutex_create("lock", 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;
}

生产者消费者问题,问题的关键为线程同步问题,OS系统中一定会遇到的问题。生产者和消费者都会用到同一组空间,只有空间内有生产者生产的东西,消费者去这个空间获取东西才有意义;只有仓库还没有装满,生产者生产出东西才有意义;生产者和消费者不能同时操作仓库内数据那么就可以列出来这五组要求:

1.仓库有空位,生产者可以生产。

2.仓库里有货位,消费者可以获取。

3.仓库是满的,阻塞生产者线程。

4.仓库是空的,阻塞消费者线程。

5.仓库不能同时产者和消费者占有。

因为仓库的空间是有固定大小的,一组信号量还不能保证仓库的具体大小。所以用两组信号量来确定仓库的大小和仓库内的库存数量。用一组互斥锁来控制仓库的同时访问。当然例程用三组信号量来完成,理论上是可行的,因为互斥锁就是信号量的一种特殊模式,不过既然有互斥锁,还是用互斥锁的舒服。

猜你喜欢

转载自blog.csdn.net/xiangxistu/article/details/82827514
今日推荐