例说生产者和消费者模型
什么是生產(chǎn)者和消費(fèi)者模型
什么是生產(chǎn)者消費(fèi)者模型?生產(chǎn)者和消費(fèi)是操作系統(tǒng)中一種重要的模型,它描述的是一種等待和通知的機(jī)制,如下圖。
生產(chǎn)者和消費(fèi)者模型必須具有的條件
用一句話概括,生產(chǎn)者消費(fèi)者模型必須具有的條件是三種關(guān)系,兩類角色,一類交易場(chǎng)所。
一類交易場(chǎng)所:交易場(chǎng)所指的是生產(chǎn)者和消費(fèi)者之間進(jìn)行數(shù)據(jù)交換的倉庫,這塊倉庫相當(dāng)于一個(gè)緩沖區(qū),生產(chǎn)者負(fù)責(zé)把數(shù)據(jù)放入到緩沖區(qū)中,消費(fèi)者負(fù)責(zé)把緩沖區(qū)中的數(shù)據(jù)取出來;
兩類角色:指的是生產(chǎn)者和消費(fèi)者;
三種關(guān)系:三種關(guān)系分別指的是:消費(fèi)者和消費(fèi)者,生產(chǎn)者和生產(chǎn)者,生產(chǎn)者和消費(fèi)者;其中消費(fèi)者和消費(fèi)者,生產(chǎn)者和生產(chǎn)者之間都屬于競(jìng)爭關(guān)系,生產(chǎn)者和消費(fèi)者之間的關(guān)系相當(dāng)于是一種食物鏈之間的依賴關(guān)系。
生產(chǎn)者和消費(fèi)者模型的特點(diǎn)
什么是條件變量
條件變量是線程可用的一種同步機(jī)制,它給多個(gè)線程提供了一個(gè)會(huì)合的場(chǎng)所,與互斥量一起使用時(shí),允許線程以無競(jìng)爭的方式等待特定條件發(fā)生。
條件本身是由互斥量保護(hù)的,線程在該變條件狀態(tài)之前必須首先鎖住互斥量,使臨界區(qū)域只能被當(dāng)前訪問資源的線程所獨(dú)有,其他線程在訪問臨界區(qū)域獲得互斥量之前不會(huì)察覺到這種改變,因?yàn)?strong>互斥量必須在鎖定以后才能計(jì)算條件。
條件變量的類型:pthread_cond_t
條件變量的初始化:條件變量的初始化有兩種方法,1.可以使用PTHREAD_COND_INITIALIZER宏來進(jìn)行初始化。2.可以使用pthread_cond_init函數(shù)來進(jìn)行初始化。
條件變量的初始化函數(shù)和摧毀函數(shù)
int pthread_cond_destroy(pthread_cond_t *cond);int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr); //兩個(gè)函數(shù)都是成功返回0,失敗則返回錯(cuò)誤碼條件變量的操作函數(shù)
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);//兩個(gè)函數(shù)都是成功返回0,失敗則返回錯(cuò)誤碼pthread_cond_wait
該函數(shù)用來使用傳遞給它的互斥量來對(duì)條件進(jìn)行保護(hù),它主要做下面的事情:
1. 把調(diào)用線程放到等待條件的線程列表上;
2. 對(duì)互斥量進(jìn)行解鎖;
3. 函數(shù)返回時(shí),互斥量再次被鎖住。
pthread_cond_timewait
相比于上面的wait函數(shù),timewait函數(shù)只是做了超時(shí)檢查,超時(shí)值abstime指定了我們?cè)敢獾却嚅L時(shí)間.這個(gè)時(shí)間是一個(gè)絕對(duì)數(shù).
如果超時(shí)了,等待的條件還是沒有出現(xiàn),那么pthread_cond_timedwait將重新獲得互斥量,并返回錯(cuò)誤碼ETIMEDOUT.
當(dāng)著兩個(gè)函數(shù)調(diào)用成功并返回時(shí),線程需要重新計(jì)算條件,因?yàn)榱硪粋€(gè)線程有可能會(huì)改變這個(gè)條件變量。
喚醒函數(shù)
int pthread_cond_broadcast(pthread_cond_t *cond);int pthread_cond_signal(pthread_cond_t *cond);//return val:成功返回0,失敗則返回錯(cuò)誤編號(hào)其中signal函數(shù)至少能喚醒一個(gè)在條件變量上等待的線程。而broadcast函數(shù)則能喚醒在條件變量上等待的所有線程.
模型具體實(shí)例
案例:我們做這樣一件事,用線程來模擬生產(chǎn)者和消費(fèi)者,鏈表來模擬他們之間進(jìn)行數(shù)據(jù)交換的場(chǎng)所,我們讓生產(chǎn)者緩慢的往“倉庫”中存儲(chǔ)數(shù)據(jù),而消費(fèi)者很快的讀取倉庫中的數(shù)據(jù),在我們不使用條件變量的情況下我們來觀察下結(jié)果:
當(dāng)我們使用條件變量后結(jié)果如下:
很明顯,使用了條件變量的程序能夠做到生產(chǎn)者寫一次數(shù)據(jù),消費(fèi)者讀一次數(shù)據(jù),不管消費(fèi)者或生產(chǎn)者執(zhí)行的有多慢或者多快(大家可以做下驗(yàn)證),而不使用條件變量的結(jié)果中,如果消費(fèi)者執(zhí)行過快,那么消費(fèi)者會(huì)不斷的訪問這塊空的資源,如果生產(chǎn)者執(zhí)行過快,那么生產(chǎn)者會(huì)頻繁的訪問“滿的倉庫”,所以說本例子中,條件變量解決了消費(fèi)者和生產(chǎn)者模型中的特點(diǎn)問題。而消費(fèi)者和生產(chǎn)者之間的互斥是由互斥量所保證的。
實(shí)例代碼
//單鏈表的函數(shù)文件
#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__//生產(chǎn)者和消費(fèi)者問題源文件
/*************************************************************************> File Name: product_consumer.c> Author: LZH> Mail: 597995302@qq.com > 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; }總結(jié)
以上是生活随笔為你收集整理的例说生产者和消费者模型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 查询自己电脑的IP地址
- 下一篇: zoj3380 Patchouli's