RT-Thread學習記錄8 生產者消費者問題

以下爲看視頻筆記..........

1.生產者消費者問題模型

生產者消費者問題是一個經典的、多線程同步問題。

有兩個線程: - -個生產者線程和一個消費者線程。兩個線程共享-個初始爲空、固定大小爲n的緩存區。.

生產者的工作是“生產”-段數據,只有緩衝區沒滿時,生產者才能把消息放入到緩衝區,否則必須等待,如此反覆;

同時,只有緩衝區非空時,消費者才能從中取出數據,- 次消費- -段數據, 否則必須等待,如此反覆。

問題的核心是:

1.1 要保證不讓生產者在緩存還是滿的時候仍然要向內寫數據;

1.2 不讓消費者試圖從空的緩存中取出數據。

2. 生產者消費者問題本質

 

解決生產者消費者問題實際上是要解決線程間互斥關係問題(指的是共享資源)同步關係問題(線程的步調)

由於緩衝區是臨界資源,它一個時刻只允許-一個生產者放入消息,或者--個消費者從中取出消息,所以這裏我們需要解決一個互斥訪問的問題。

同時生產者和消費者又是一- 個相互協作的關係,只有生產者生產之後,消費者才能消費,所以我們還需要解決一個同步的問題。

二值信號量指的是value值爲0或1,實現共享資源的互斥。首先把value值初始化爲1, 生產者線程訪問共享資源時,他先獲取二值信號量的值,因爲value初始化爲1,生產者可以操作共享資源;當這時候消費者線程去獲取共享資源時,此時value值被生產者賦值爲0了,所以消費者是獲取不到共享資源的,達到共享資源保護的作用。

3. 實例代碼

在produer_consumer.c中

/*
 * 程序清單:生產者消費者例子
 *
 * 這個例子中將創建兩個線程用於實現生產者消費者問題
 *(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);  //sem_empty的value值爲5

        /* 修改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);//sem_full的初始值爲0的

        /* 臨界區,上鎖進行操作 */
        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);

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章