生产者与消费者模型

article/2025/9/28 7:28:52

1、【什么是生产者与消费者模型呢?】

一种重要的模型,基于等待/通知机制。生产者/消费者模型描述的是有一块缓冲区作为仓库,生产者可将产品放入仓库,消费者可以从仓库中取出产品,生产者/消费者模型关注的是以下几个点:
1、生产者与消费者不能同时进行工作,形成的是互斥关系;
2、生产者与生产者之间不能同时生产,处于互斥关系;
3、消费者与消费者之间不能同时工作,处于互斥关系;
4、当缓冲区之内的资源满时,生产者不能生产;
5、当缓冲区之内的资源空时,消费者不能消费;
6、消费者消费的速度不能超过生产者;
形象图显示:
                                                        
2、【生产者与消费者之间的关系】
基于消费者与生产者模型的概念;在形成了三种关系 、两个对象、一种机制 我们称之为是321原则
、、、三种关系指的是:
生产者与消费者关系、生产者与生产者关系、消费者与消费者的关系(三种关系都是互斥关系);
、、、两个对象指的是:
生产者对象、消费者对象
、、、一种机制指的是:
互斥机制

3、【实现单生产者与单消费者模型】

基于单链表实现:
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>//mutex设置锁,来实现生产者与消费者的互斥关系
pthread_mutex_t  lock  = PTHREAD_MUTEX_INITIALIZER;
//cond设置条件变量
pthread_cond_t  cond = PTHREAD_COND_INITIALIZER;//定义一个 链表
typedef struct Node
{int _val;struct  Node *  _next;
}Node_t,*Node_p,**Node_pp;Node_p head = NULL;
/链表的实现/
Node_p allocNode(int val)
{Node_p ret =  (Node_p)malloc(sizeof(Node_t));ret->_val = val;ret->_next = NULL;return ret;
}void  freeNode(Node_p del)
{free(del);
}
int initList(Node_pp _head)
{*_head = allocNode(0);if(*_head == NULL)return 0;return -1;
}void PushNode(Node_p  _head,int val)
{Node_p  node = allocNode(val);node->_next = _head->_next;_head->_next = node;
}
int  Empty(Node_p _head)
{return  (_head->_next==NULL)?0:-1;
}
int  PopNode(Node_p  _head,int * val)
{if(Empty(_head) == 0){return -1;}Node_p  del  = _head->_next;_head->_next = del->_next;*val  = del->_val;freeNode(del);del = NULL;return  0;
}
void PrintList(Node_p _head)
{Node_p tmp = _head->_next;while(tmp){printf("%d ",tmp->_val);tmp=tmp->_next;}printf("\n");
}void DestroyList(Node_pp _head)
{while(Empty(*_head) < 0){int tmp;PopNode(*_head,&tmp);}freeNode(*_head);*_head = NULL;
}
//
//生产者者 插入数据
void * producter(void * arg)
{while(1){pthread_mutex_lock(&lock);int val =  rand()%1024;PushNode(head,val);printf("producter push done: %d \n",val);sleep(1);//生产者 插入数据,此时唤醒消费者消费pthread_cond_signal(&cond);pthread_mutex_unlock(&lock);}	return  NULL;
}
//消费者弹出数据
void * consumer(void *  arg)
{while(1){pthread_mutex_lock(&lock);if(Empty(head)==0){	//要是当前的链表为空printf("consumer  check\n");//消费者使用 条件变量 挂起pthread_cond_wait(&cond,&lock);}else{int val;PopNode(head,&val);printf("producter pop done: %d \n",val);}//sleep(1);pthread_mutex_unlock(&lock);}
}
int main()
{/*initList(&head);int count = 0 ;while(count++ <10){//int val = rand()%1024;PushNode(head,count);PrintList(head);sleep(1);}count = 0 ;while(count ++ < 7){int val ;PopNode(head,&val);PrintList(head);sleep(1);}DestroyList(&head);*/initList(&head);pthread_t c,p;pthread_create(&c,NULL,consumer,NULL);pthread_create(&p,NULL,producter,NULL);pthread_join(c,NULL);pthread_join(p,NULL);	DestroyList(&head);pthread_mutex_destroy(&lock);pthread_cond_destroy(&cond);return   0 ;
}
基于环形队列实现:
#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>//使用信号量实现环形队列
int databuf[64];
sem_t  semblank;//信号量 格子数
sem_t  semdata;//信号量 数据数量void *  consumer(void  *arg)
{int step  = 0;while(1){if(sem_wait(&semdata) <0){printf("consumer check!\n");}else{int data = databuf[step];step++;step %= 64;	printf("consumer done :%d \n",data);sem_post(&semblank);}usleep(500000);}return NULL;
}
void *  producter(void  *arg)
{int step  = 0 ;while(1){	if(sem_wait(&semblank)< 0 ){printf("producter check! \n");}else{int data= rand()%1234;databuf[step] = data;step++;step %= 64;printf("producter done :%d \n",data);sem_post(&semdata);}usleep(1);}return NULL;
}
int main()
{//初始化两个信号值 格子数是 64 ,数据量为 0sem_init(&semblank,0,64);sem_init(&semdata,0,0);pthread_t  c,p;pthread_create(&c,NULL,consumer,NULL);pthread_create(&p,NULL,producter,NULL);pthread_join(c,NULL);pthread_join(p,NULL);sem_destroy(&semblank);sem_destroy(&semdata);	return  0;
}

4、【实现多生产者与消费者模型】

在这有两个生产者与两个消费者 
#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>
//实现多生产者 、多消费者
//使用信号量实现环形队列
int databuf[64];
sem_t  semblank;//信号量 格子数
sem_t  semdata;//信号量 数据数量//生产者与生产者是 互斥关系;
//消费者与消费者是 互斥关系;
//互斥锁
pthread_mutex_t  conlock =PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t  prolock =PTHREAD_MUTEX_INITIALIZER;
int stepc = 0 ;//consumer  step ;
int stepp = 0 ;//productor step ;void *  consumer1(void  *arg)
{while(1){pthread_mutex_lock(&conlock);if(sem_wait(&semdata) <0){printf("consumer1 check!\n");}else{int data = databuf[stepc];stepc++;stepc %= 64;	printf("consumer1 done :%d \n",data);sem_post(&semblank);}usleep(500000);pthread_mutex_unlock(&conlock);}return NULL;
}
void *  consumer2(void  *arg)
{while(1){pthread_mutex_lock(&conlock);if(sem_wait(&semdata) <0){printf("consumer2 check!\n");}else{int data = databuf[stepc];stepc++;stepc %= 64;	printf("consumer2 done :%d \n",data);sem_post(&semblank);}sleep(1);pthread_mutex_unlock(&conlock);}return NULL;
}void *  producter1(void  *arg)
{while(1){	pthread_mutex_lock(&prolock);if(sem_wait(&semblank)< 0 ){printf("producter1 check! \n");}else{int data= rand()%1234;databuf[stepp] = data;stepp++;stepp %= 64;printf("producter1 done :%d \n",data);sem_post(&semdata);}sleep(1);pthread_mutex_unlock(&prolock);}return NULL;
}
void *  producter2(void  *arg)
{while(1){	pthread_mutex_lock(&prolock);if(sem_wait(&semblank)< 0 ){printf("producter2 check! \n");}else{int data= rand()%1234;databuf[stepp] = data;stepp++;stepp %= 64;printf("producter2 done :%d \n",data);sem_post(&semdata);}sleep(1);pthread_mutex_unlock(&prolock);		}return NULL;
}
int main()
{//初始化两个信号值 格子数是 64 ,数据量为 0sem_init(&semblank,0,64);sem_init(&semdata,0,0);pthread_t  c1,p1,c2,p2;pthread_create(&c1,NULL,consumer1,NULL);pthread_create(&p1,NULL,producter1,NULL);pthread_create(&c2,NULL,consumer2,NULL);pthread_create(&p2,NULL,producter2,NULL);pthread_join(c1,NULL);pthread_join(p1,NULL);pthread_join(c2,NULL);pthread_join(p2,NULL);sem_destroy(&semblank);sem_destroy(&semdata);	pthread_mutex_destroy(&conlock);pthread_mutex_destroy(&prolock);return  0;
}

5、【实现进程之间的单生产者与单消费者模型】

进程之间实现生产者与消费者模型:在这里要使用到进程通信;
在这里我是使用的是   共享内存  来实现进程之间的通信的,但是,共享内存不提供任何的同步与互斥机制,所以我还是用到  信号量 来实现互斥机制
实现 共享内存 与 信号量
#ifndef  _COMM_H_
#define  _COMM_h_#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/sem.h>#define  PATHNAME "."
#define  PROJ_ID 0x0666//实现信号量 与共享内存的函数声明int creatshm(int size);
int getshm(int size);
void *  attshm(int shmid);
int dttshm(void *addr);
int destroyshm(int shmid);union semun {int              val;    /* Value for SETVAL */struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */unsigned short  *array;  /* Array for GETALL, SETALL */struct seminfo  *__buf;  /* Buffer for IPC_INFO (Linux-specific) */
};int creatSem(int nsems);
int getSem(int nsems);
int destroySem(int semid);
int initSem(int semid,int which,int value);
int P(int semid,int which);
int V(int semid,int which);#endif
#include"comm.h"//Sem
static  int  commSem(int flag,int nsems)
{key_t  key = ftok(PATHNAME,PROJ_ID);if(key <  0){perror("ftok");return  -1;}int semid = semget(key,nsems,flag);if(semid < 0 ){perror("semget");return  -2;}return  semid;
}
//创建的信号量
int creatSem(int nsems)
{return commSem(IPC_CREAT|IPC_EXCL|0666,nsems);
}
//得到已创建的信号量
int getSem(int nsems)
{return commSem(IPC_CREAT,nsems);
}
//销毁信号量集
int destroySem(int semid)
{if(semctl(semid,0,IPC_RMID)  < 0 ){perror("semctl");return -1;}return  0;}
//信号量集的初始化
int initSem(int semid ,int which,int value)
{union semun _semun;_semun.val = value;if(semctl(semid,which,SETVAL,_semun) < 0 ){perror("semctl");return -1;}return 0;
}
int  Semop(int semid,int which,int op)
{struct  sembuf  _sembuf;_sembuf.sem_num = which;_sembuf.sem_op = op;_sembuf.sem_flg =  0;return  semop(semid,&_sembuf,1);
}int P(int semid,int which)
{if(Semop(semid,which ,-1) ==0 )return  0;perror("P_sem");return  -1;
}int V(int semid,int which)
{if(Semop(semid,which ,1) == 0 )return  0;perror("V_sem");return  -1;
}//shm
static  int commshm(int flag,int size)
{key_t key=ftok(PATHNAME,PROJ_ID);if(key < 0){perror("ftok");return -1;}int shmid  = shmget(key,size,flag);if(shmid<0){perror("shmget");}return shmid;
}
//创建共享内存
int creatshm(int size)
{return commshm(IPC_CREAT|IPC_EXCL|0666,size);}
//得到共享内存
int getshm(int size)
{return commshm(IPC_CREAT,size);}
//销毁共享内存
int destroyshm(int shmid)
{if(shmctl(shmid,IPC_RMID,NULL) < 0 ){perror("shmctl");return -1;}return  0;
}
//搭接到共享内存
void * attshm(int shmid)
{void * shmaddr = shmat(shmid,NULL,0);return  shmaddr;}
//断开连接
int  dttshm(void  *addr)
{return  shmdt(addr);
}
实现生产者函数
#include"comm.h"//conducter put data 
int main()
{//  creat shmint  shmid = creatshm(4096);int  *addr= (int *)attshm(shmid);int step = 0;//  creat  semint  semid = creatSem(2);//consumer sem blank 64initSem(semid,0,64);//server  sem data 0;initSem(semid,1,0);;while(1){P(semid,0);int data  = rand()%1234;addr[step] = data;++step;step %= 64;printf("conducter done : %d! \n",data);sleep(1);V(semid,1);}dttch(addr);destroySem(semid);destroyshm(shmid);return  0;}
实现消费者
#include"comm.h"//consumer get  data 
int main()
{//  get shmint  shmid = getshm(4096);int  *addr= (int *)attshm(shmid);//  get  semint semid = getSem(2);int step = 0 ;while(1){P(semid,1);int data  =	addr[step] ;++step;step %= 64;printf("consumer done : %d! \n",data);sleep(1);V(semid,0);}dttch(addr);return  0;}



http://chatgpt.dhexx.cn/article/gBsuegEr.shtml

相关文章

生产者消费者模型——C语言代码详解

概念 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯&#xff0c;而通过阻塞队列来进行通讯&#xff0c;所以生产者生产完数据之后不用等待消费者处理&#xff0c;直接扔给阻塞队列&#xff0c;消费者不找生产者要数据…

【Java总结】生产者消费者模型

生产者消费者模型主要结构如下&#xff0c;是一个典型的线程同步的案例。下面就来使用java做几种线程同步的方式来实现以下该模型 确保一个生产者消费者模型的稳定运行的前提有以下几个 生成者应该具备持续生成的能力消费者应该具备持续消费的能力生产者的生成和消费消费有一定…

【设计模式】生产者消费者模型

带你轻松理解生产者消费者模型&#xff01;生产者消费者模型可以说是同步与互斥最典型的应用场景了&#xff01;文末附有模型简单实现的代码&#xff0c;若有疑问可私信一起讨论。 文章目录 一&#xff1a;为什么要使用生产者消费者模型&#xff1f;二&#xff1a;生产者消费者…

模拟生产者消费者模型

生产者消费者是多线程很经典的一个模型 牵涉三个对象&#xff1a;仓库、生产者、消费者 仓库代表共享变量 生产者表示在仓库生产货物 消费者表示从仓库拿出货物 实现思路&#xff1a;利用synchronizedwait()notify() 对生产者消费者对应的操作用synchronized关键字保证线程安全…

生产者消费者模型java实现

做题的时候遇到了生产者消费者问题&#xff0c;这个问题可以说是线程学习的经典题目了&#xff0c;就忍不住研究了一波。它描述是有一块缓冲区&#xff08;队列实现&#xff09;作为仓库&#xff0c;生产者可以将产品放入仓库&#xff0c;消费者则可以从仓库中取走产品。在Java…

生产者消费者模型详解以及实现

生产者消费者模式 我们先来看看什么是生产者消费者模式&#xff0c;生产者消费者模式是程序设计中非常常见的一种设计模式&#xff0c;被广泛运用在解耦、消息队列等场景。在现实世界中&#xff0c;我们把生产商品的一方称为生产者&#xff0c;把消费商品的一方称为消费者&…

Java生产者消费者模型的五种实现方式

转自&#xff1a;https://juejin.im/entry/596343686fb9a06bbd6f888c 前言 生产者和消费者问题是线程模型中的经典问题&#xff1a;生产者和消费者在同一时间段内共用同一个存储空间&#xff0c;生产者往存储空间中添加产品&#xff0c;消费者从存储空间中取走产品&#xff0c…

生产者消费者模型---详解及代码实现

概念 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯&#xff0c;而通过阻塞队列来进行通讯&#xff0c;所以生产者生产完数据之后不用等待消费者处理&#xff0c;直接扔给阻塞队列&#xff0c;消费者不找生产者要数据…

生产消费者模型

生产消费者模型中包含三个部分&#xff0c;生产者、消费者和交易场所。其中涉及如下的关系&#xff1a; &#xff08;1&#xff09;生产者和生产者之间的关系&#xff1a;由于生产者的生产面向的都是交易场所&#xff0c;所以生产者之间是存在竞争关系的&#xff0c;就像一家超…

生产者-消费者模型

什么是生产者消费者模型 生产者 - 消费者模型&#xff08; Producer-consumer problem&#xff09; 是一个非常经典的多线程并发协作的模型&#xff0c;在分布式系统里非常常见。 这个模型由两类线程和一个缓冲区组成来组成 生产者线程&#xff1a;生产数据&#xff0c;并把…

最长上升子序列和最长公共子序列

文章目录 文章目录 文章目录一、基本知识二、最长上升子序列1.朴素版2.二分版 三、最长公共子序列 一、基本知识 1.子串和子序列的区别&#xff1a; 子串必须连续,子序列可以不连续。 2.最长上升子序列(LIS)&#xff1a; 是指一个序列中最长的单调递增的子序列。 3.最长公共…

求最长子序列及回溯

D - 最长公共子序列问题 Description 给定两个序列 X{x1,x2,…,xm} 和 Y{y1,y2,…,yn}&#xff0c;找出X和Y的最长公共子序列。 Input 输入数据有多组&#xff0c;每组有两行 &#xff0c;每行为一个长度不超过500的字符串&#xff08;输入全是大写英文字母&#xff08;A,Z…

算法14-求最长子序列

题目&#xff1a; 给定数组arr。求最长的有序子序列的长度&#xff0c;返回长度int 分析&#xff1a; 1 要求的子串是有序的&#xff0c;就要比大小 2 用最暴力大方法&#xff0c;看成窗口问题&#xff0c;每一个元素求出它左边的最长序列子串&#xff0c;写入一个数组dp&…

最长子序列——动态规划

动态规划算法通常用于求解具有某种最优性质的问题。动态规划算法与分治法类似&#xff0c;其基本思想也是将待求解问题分解成若干个子问题&#xff0c;先求解子问题&#xff0c;然后从这些子问题的解得到原问题的解。与分治法不同的是&#xff0c;适合于用动态规划求解的问题&a…

最长公共子串与最长子序列

一 序 本文属于《图解算法》系列&#xff0c;上一篇整理了动态规划&#xff0c;动态规划可以帮助我们解决给定约束条件下找到最优解&#xff0c;例如背包问题。 在问题可分解为彼此独立且离散的子问题时&#xff0c;就可使用动态规划来解决。 在看个例子&#xff0c;求两个字…

动态规划:最长子序列

最长公共子序列&#xff1a; 链接&#xff1a;https://www.nowcoder.com/questionTerminal/9ae56e5bdf4f480387df781671db5172 题目&#xff1a; 我们有两个字符串m和n&#xff0c;如果它们的子串a和b内容相同&#xff0c;则称a和b是m和n的公共子序列。子串中的字符不一定在原字…

C++最长子序列

LeedCode-300. 最长上升子序列 LeetCode-300. 最长上升子序列 方法一&#xff1a;O(n^2)可能会超时&#xff1b;方法二&#xff1a;贪心二分法&#xff0c;使用lower_bound()&#xff1b; 下面是贪心二分算法&#xff1a; 由于要得到最长的递增子序列&#xff0c;就要让序列…

数组:最长子序列问题四种解法

数组&#xff1a;最长子序列问题四种解法 问题描述&#xff1a; 给定一个整数数组 nums &#xff0c;找到一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 示例 1 : 输入: [-2,1,-3,4,-1,2,1,-5,4], 输出: 6 解释: 连续子…

动态规划:最长子序列问题

关于动态规划中的最长子序列问题有很多优秀的解读&#xff0c;在这里推荐一位博主的关于最长子序列的文章&#xff0c;非常不错&#xff0c;配有大量的图片和文字解答&#xff0c;在这里推荐给大家。本文章转载自这里 1.基本概念 首先需要科普一下&#xff0c;最长公共子序列…

一道有趣的最长子序列问题

一道有趣的最长子序列问题 – 潘登同学的金融经济学笔记 文章目录 一道有趣的最长子序列问题 -- 潘登同学的金融经济学笔记 来源求解递推公式算法实现 来源 前几天在刷视频的时候&#xff0c;发现了这样一道题 所谓子序列就是一个序列 a i 1 , a i 2 , ⋯ , a i n a_{i1},a_{…