Linux下生產者與消費者模型

1. 概念
  有一個或多個生產者生產某種類型的數據,並放在緩衝區裏(生產者),有一個消費者從緩衝區中取數據,每次取一項(消費者)。系統保證任何時候只有一個主題可以訪問緩存區。所以當生產滿時,生產者不會再生產數據;當緩衝區爲空時,消費者不會從中移走數據。 接下來解釋同步和互斥的概念,然後用代碼(鏈表、環形隊列)模擬生產者與消費者的關係。
  互斥與同步:假設兩個或者更多的進程需要訪問一個不可共享的資源,如打印機。在執行過程中,每個進程都給該I/O設備發命令,接收狀態信息,收發數據。我們把這類資源叫做臨界資源,使用臨界資源的那一部分程序叫做程序的臨界區。而一次只允許一個程序在臨界區,即實現原子性(原子性爲對外不可分)訪問。而使它門有序的進行訪問爲同步
2. 生產者與消費者模型
  生產者與生產者之間爲互斥關係,消費者與消費者之間爲互斥,生產者與消費者之間爲爲同步、互斥。關係圖爲:


1) 使用鏈表模擬
  我們採用鏈表的頭插和頭刪來模擬生產數據和消費數據這兩個過程。大致流程如下:

代碼如下:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>

typedef struct List
{
    int _data;
    struct List* _next;
}List,*pList;

pList getNode(int d)
{
    pList node = (pList)malloc(sizeof(List));
    if(node == NULL)
    {
        perror("malloc");
        exit(1);
    }
    node->_data = d;
    node->_next = NULL;
    return node;
}

void pushFront(int d, pList* pplist)
{
    pList node=  getNode(d);
    if(*pplist == NULL)
        *pplist = node;
    else
    {   
        node->_next = *pplist;
        *pplist = node;
    }
}

void  popFront(pList* pplist, int *data)
{
    pList cur = *pplist;
    if(cur == NULL)
    {
        exit(1);
    }
    while(cur->_next == NULL)
    {
       *data = cur->_data;
        free(cur);
        cur == NULL;
        exit(2);
    }
    *pplist = cur->_next;
    *data = cur->_data;
    free(cur);
}

int isEmpty(pList l)
{
    if(l == NULL)
    {
        return 1;
    }
    return 0;
}

void desList(pList* pplist)
{
    pList cur = *pplist;
    pList del = NULL;
    while(cur != NULL)
    {
        del = cur;
        cur = cur->_next;
        free(del);
        del = NULL;
    }
    *pplist = NULL;
}

//靜態方式創建,賦予常量
pthread_cond_t mycond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
pList list = NULL;

void* consume(void* arg)
{
    int data = 0;
    while(1)
    {
        sleep(2);
        //阻塞式加鎖
        pthread_mutex_lock(&mylock);
        while(isEmpty(list))
        {
            //條件不滿足時,進入阻塞式等待
            pthread_cond_wait(&mycond, &mylock);
        }
        popFront(&list,&data);
        printf("consume get : %d\n",data);
        //解鎖
        pthread_mutex_unlock(&mylock);
    }
}

void* product( void* arg)
{
    int data = 0;
    while(1)
    {
        pthread_mutex_lock(&mylock);
        data = rand()%100;
        pushFront(data,&list);
        printf("product put : %d\n",data);
        pthread_mutex_unlock(&mylock);
        //激活一個等待該條件的線程
        pthread_cond_signal(&mycond);
        sleep(1);
    }
}

int main()
{
    pthread_t tid1,tid2;
    //線程的創建與等待
    pthread_create(&tid1, NULL, consume, NULL);
    pthread_create(&tid2, NULL, product, NULL);
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    desList(&list);

    pthread_mutex_destroy(&mylock);
    //沒有線程在該條件變量上等待的時候註銷這個條件
    //變量,否則返回EBUSY
    pthread_cond_destroy(&mycond);
    return 0;
}

2)環形隊列實現
實現流程如下:


代碼如下:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <semaphore.h>
#define SIZE 4

int stor[SIZE];
//創建信號量
sem_t blankSem;
sem_t dataSem;

void* consumer()
{
    int step = 0;
    int data = 0;
    while(1)
    {
        sleep(1);
        //等待數據信號量
        sem_wait(&dataSem);
        data = stor[step++];
        //釋放空格信號量
        sem_post(&blankSem);
        step %= SIZE;
        printf("consumer get: %d\n",data);
    }
}
void* producter()
{
    int step = 0;
    int data = 0;
    while(1)
    {
        sem_wait(&blankSem);
        stor[step++] = data++;
        sem_post(&dataSem);
        step %= SIZE;
        printf("producter put: %d\n",data);
    }
}
int main()
{
    //初始化信號量,格子SIZE個,數據0個
    sem_init(&blankSem, 0, SIZE);
    sem_init(&dataSem, 0, 0);
    pthread_t td1,td2;
    //創建和等待線程
    pthread_create(&td1, NULL, consumer, NULL);
    pthread_create(&td2, NULL, producter, NULL);
    pthread_join(td1, NULL);
    pthread_join(td2, NULL);
    //銷燬信號量
    sem_destroy(&blankSem);
    sem_destroy(&dataSem);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章