1. 程式人生 > >Linux下生產者與消費者模型

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;
}