例說生產者和消費者模型

什麼是生產者和消費者模型

什麼是生產者消費者模型?生產者和消費是操作系統中一種重要的模型,它描述的是一種等待和通知的機制,如下圖。
(生產者和消費者模型)


生產者和消費者模型必須具有的條件

用一句話概括,生產者消費者模型必須具有的條件是三種關係,兩類角色,一類交易場所
一類交易場所:交易場所指的是生產者和消費者之間進行數據交換的倉庫,這塊倉庫相當於一個緩衝區,生產者負責把數據放入到緩衝區中,消費者負責把緩衝區中的數據取出來;
兩類角色:指的是生產者和消費者;
三種關係:三種關係分別指的是:消費者和消費者,生產者和生產者,生產者和消費者;其中消費者和消費者,生產者和生產者之間都屬於競爭關係,生產者和消費者之間的關係相當於是一種食物鏈之間的依賴關係。

生產者和消費者模型的特點

  1. 首先,生產者只需要關心“倉庫”,並不需要關心具體的消費者。
  2. 對於消費者而言,它不需要關心具體的生產者,它只需要關心這個“倉庫”中還有沒有東西存在。
  3. 生產者生產的時候消費者不能進行“消費”,消費者消費的時候生產者不能生產,相當於一種互斥關係,即生產者和消費者一次只能有一人能訪問到“倉庫”。
  4. “倉庫”爲空時不能進行消費。
  5. “倉庫”滿時不能進行生產。

什麼是條件變量

條件變量是線程可用的一種同步機制,它給多個線程提供了一個會合的場所,與互斥量一起使用時,允許線程以無競爭的方式等待特定條件發生。
條件本身是由互斥量保護的,線程在該變條件狀態之前必須首先鎖住互斥量,使臨界區域只能被當前訪問資源的線程所獨有,其他線程在訪問臨界區域獲得互斥量之前不會察覺到這種改變,因爲互斥量必須在鎖定以後才能計算條件

條件變量的類型:pthread_cond_t
條件變量的初始化:條件變量的初始化有兩種方法,1.可以使用PTHREAD_COND_INITIALIZER宏來進行初始化。2.可以使用pthread_cond_init函數來進行初始化。

條件變量的初始化函數和摧毀函數

  int pthread_cond_destroy(pthread_cond_t *cond);

int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
//兩個函數都是成功返回0,失敗則返回錯誤碼

條件變量的操作函數

       int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime);

       int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);

       //兩個函數都是成功返回0,失敗則返回錯誤碼

pthread_cond_wait

該函數用來使用傳遞給它的互斥量來對條件進行保護,它主要做下面的事情:
1. 把調用線程放到等待條件的線程列表上;
2. 對互斥量進行解鎖;
3. 函數返回時,互斥量再次被鎖住。

pthread_cond_timewait

相比於上面的wait函數,timewait函數只是做了超時檢查,超時值abstime指定了我們願意等待多長時間.這個時間是一個絕對數.
如果超時了,等待的條件還是沒有出現,那麼pthread_cond_timedwait將重新獲得互斥量,並返回錯誤碼ETIMEDOUT.

當着兩個函數調用成功並返回時,線程需要重新計算條件,因爲另一個線程有可能會改變這個條件變量。

喚醒函數


       int pthread_cond_broadcast(pthread_cond_t *cond);
       int pthread_cond_signal(pthread_cond_t *cond);

       //return val:成功返回0,失敗則返回錯誤編號

其中signal函數至少能喚醒一個在條件變量上等待的線程。而broadcast函數則能喚醒在條件變量上等待的所有線程.

模型具體實例

案例:我們做這樣一件事,用線程來模擬生產者和消費者,鏈表來模擬他們之間進行數據交換的場所,我們讓生產者緩慢的往“倉庫”中存儲數據,而消費者很快的讀取倉庫中的數據,在我們不使用條件變量的情況下我們來觀察下結果:
這裏寫圖片描述

當我們使用條件變量後結果如下:
這裏寫圖片描述


很明顯,使用了條件變量的程序能夠做到生產者寫一次數據,消費者讀一次數據,不管消費者或生產者執行的有多慢或者多快(大家可以做下驗證),而不使用條件變量的結果中,如果消費者執行過快,那麼消費者會不斷的訪問這塊空的資源,如果生產者執行過快,那麼生產者會頻繁的訪問“滿的倉庫”,所以說本例子中,條件變量解決了消費者和生產者模型中的特點問題。而消費者和生產者之間的互斥是由互斥量所保證的。

實例代碼

//單鏈表的函數文件

#include "myList.h"

Node_p AllocNode(int data)
{
    Node_p NewNode=(Node_p)malloc(sizeof(Node));
    if(NewNode==NULL)
    {
        perror("malloc..\n");
        return ;
    }
    NewNode->data=data;
    NewNode->next=NULL;

    return NewNode;
}

int IsEmpty(Node_p list)
{
    assert(list);
    if(list->next!=NULL)
    {
        return 0;
    }
    else
    {
        return 1;
    }
}

void ListInit(Node_pp head)
{
    *head=AllocNode(0); 
}

void PushHead(Node_p list,int data)
{
    assert(list);

    Node_p NewNode=AllocNode(data);
    NewNode->next=list->next;
    list->next=NewNode;
}

void DelNode(Node_p node)
{
    assert(node);
    free(node);
    node=NULL;
}

void PopHead(Node_p list,int *data)
{
    assert(data);
    if(IsEmpty(list))
    {
        printf("the list empty..\n");
        return;
    }
    Node_p dNode=list->next;
    list->next=dNode->next;
    *data=dNode->data;
    DelNode(dNode);
}

void ShowList(Node_p list)
{   
    assert(list);
    Node_p cur=list->next;
    while(cur)
    {
        printf("%d ",cur->data);
        cur=cur->next;
    }
    printf("\n");
}


void DestroyList(Node_p list)
{
    assert(list);
    int data=0;
    while(list->next)
    {
        PopHead(list,&data);
    }

    free(list);
    list=NULL;
    printf("list is destroy...\n");
}

//單鏈表的頭文件


#ifndef __LIST_H__
#define __LIST_H__

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

typedef struct Node{
    int data;
    struct Node* next;
}Node,*Node_p,**Node_pp;

Node_p AllocNode(int data);
void ListInit(Node_pp head);
int IsEmpty(Node_p list);
void PushHead(Node_p list,int data);
void DelNode(Node_p node);
void PopHead(Node_p list,int *data);
void ShowList(Node_p list);
void DestroyList(Node_p list);
#endif //__LIST_H__

//生產者和消費者問題源文件

/*************************************************************************
    > File Name: product_consumer.c
    > Author: LZH
    > Mail: [email protected] 
    > Created Time: Sun 19 Feb 2017 12:46:44 AM PST
 ************************************************************************/

#include "myList.h"
#include <pthread.h>

pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t mycond=PTHREAD_COND_INITIALIZER;
//pthread_mutex_t mylock=PTHREAD_MUTEX_INITIALIZER;

void* pthread_Product(void* arg)
{
    Node_p head=(Node_p)arg;
    while(1)
    {
        usleep(123456);
        pthread_mutex_lock(&mylock);
        int data=rand()%1000;
        PushHead(head,data);
        printf("I am producter,%d\n",data);
        pthread_cond_signal(&mycond);       
        //ShowList(arg);
        pthread_mutex_unlock(&mylock);
    }
}

void* pthread_Consumer(void* arg)
{
    Node_p head=(Node_p)arg;
    int data=0;
    while(1)
    {
        pthread_mutex_lock(&mylock);
        //sleep(1);
        if(IsEmpty(head))
        {
            pthread_cond_wait(&mycond,&mylock);
        }
        PopHead(head,&data);
        //ShowList(head);
        //sleep(1);
        printf("I am consumer,%d\n",data);
        pthread_mutex_unlock(&mylock);
    }
}

void test()
{
    printf("product_consumer...\n");

    Node_p head;
    ListInit(&head);
    printf("head->data:%d\n",head->data);
    int i=0;
    while(i<10)
    {
        PushHead(head,i);
        i++;
        ShowList(head);
    }
    int data;
    while(i>0)
    {
        PopHead(head,&data);
        i--;
        ShowList(head);
        printf("IsEmpty?%d\n",IsEmpty(head));
    }

    DestroyList(head);
    ShowList(head);

    //return 0;
}


int main()
{
    Node_p head=NULL;
    ListInit(&head);

    pthread_t tid1,tid2;
    int ret1=pthread_create(&tid1,NULL,pthread_Product,(void*)head);
    int ret2=pthread_create(&tid2,NULL,pthread_Consumer,(void*)head);
    printf("ret1:%d,ret2:%d\n",ret1,ret2);  
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    pthread_mutex_destroy(&mylock);
    pthread_cond_destroy(&mycond);

    return 0;
}

發佈了89 篇原創文章 · 獲贊 190 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章