目录

文章目录

前言

一、实验内容

二、背景知识

三、思路

四、核心代码

1.生产者类

2.1 消费者子类1

2.2 消费者子类2

2.3 消费者子类3

3.主函数

五、源代码

六、运行结果

​编辑

七.结论


提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

前言

一、实验内容

1.问题描述

一组生产者多组消费者提供消息,它们共享一个有界缓冲池,生产者向其中投放消息,消费者从中取得消息。假定这些生产者和消费者互相等效,只要缓冲池未满,生产者可将消息送入缓冲池,只要缓冲池未空,消费者可从缓冲池取走一个消息。

2.功能要求

根据进程同步机制,编写一个解决上述问题的程序,可显示缓冲池状态、放数据、取数据等过程。

二、背景知识

生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了共享固定大小缓冲区的两个线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。

三、思路

要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采用进程间通信的方法解决该问题,常用的方法有信号灯法[1]等。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形。

四、核心代码

数据说明

int mutex = 1;          //互斥信号量// mutex =1 代表进程空闲, mutex =0代表进程正在使用
int full;               //缓冲区非空个数
const int n = 5;       //缓冲区大小为 10
int empty = n;         //空缓冲区个数
char buffer[n];         //定义缓冲区
int pfull = 0;         //产品资源非空信号量//可用于多生产者时进行区分产品类不同对应的消费
int in = 0, out = 0;  //定义存取指针的初始位置// in 指定生产产品当前的位置, out 指定消费产品当前的位置
int choose = 1;            //选择,首次产生产品P 

1.生产者类

//生产者类
class Producer
{private:int m_mutex;int m_full;int m_pfull;int m_in;public:Producer( int mu, int fu, int pfu, int pin ){m_mutex = mu;m_full = fu;m_pfull = pfu;m_in = in;}void showP(){if( mutex == 1 )//mutex = 1代表没有进程进行{if( full == n )//进程满了 {cout << "缓冲区空间已满!" << endl;exit( 0 );//退出 }mutex = 0;//mutex = 0代表有进程正在进行cout << "--------------------------------------------" << endl;cout << "生产者进程P:产生产品P" << endl;full++;//产品数量存储+1 pfull++;//生产者进程P生产数量while( buffer[in] == 'P' )//避免重复位置替换产品P {in = ( in + 1 ) % n;//循环队列计数 }buffer[ in ] = 'P';showbuffer( buffer );in = ( in + 1 ) % n;}else/// mutex = 0的情况 {cout << "进程P正在使用!" << endl;}choice();}
};

2.消费者类

//消费者类
class Consumer{private:int m_mutex;int m_full;int m_pfull;int m_out;char m_c;public:Consumer( int mu, int fu, int pfu, int ou, char c = '0' ){m_mutex = mu;m_full = fu;m_pfull = pfu;m_out = ou;m_c = c;}void showC( ){if( mutex == 1 )//mutex = 1代表没有进程进行{if( full == 0 ){cout << "没有进程可消费!" << endl;exit( 0 );}else{mutex = 0;if( pfull == 0 ){cout << " 消费者进程C没有可消费的!" << endl;exit( 0 );}else{cout << "--------------------------------------------" << endl;cout << "消费者进程C" << m_c << ":把产品P消费了->" << m_c << endl;full--;pfull--;buffer[ out ] = m_c;showbuffer( buffer );buffer[ out ] = '~';out = ( out + 1 ) % n;}}}else {cout << "进程C" << m_c << "正在使用!" << endl;}choice();
}
};

2.1 消费者子类1

//消费者类 1
class C1:public Consumer
{public:C1( int mu, int fu, int pfu, int ou, char c1 = '1' ):Consumer( mu, fu, pfu, ou, c1 ){} void showC1(){Consumer::showC();}
};

2.2 消费者子类2

//消费者类 2
class C2:public Consumer
{public:C2( int mu, int fu, int pfu, int ou, char c1 = '2' ):Consumer( mu, fu, pfu, ou, c1 ){} void showC2(){Consumer::showC();}
};

2.3 消费者子类3

//消费者类 3
class C3:public Consumer
{public:C3( int mu, int fu, int pfu, int ou, char c1 = '3' ):Consumer( mu, fu, pfu, ou, c1 ){} void showC3(){Consumer::showC();}
};

3.主函数

int main()
{Producer p( mutex, full, pfull, in );Consumer c( mutex, full, pfull, out );C1 c1( mutex, full, pfull, out );C2 c2( mutex, full, pfull, out );C3 c3( mutex, full, pfull, out );while( choose != 0 ){switch( choose ){case 1:p.showP();break;case 2:c1.showC1();break;case 3:c2.showC2();break;case 4:c3.showC3();break;}}
}

五、源代码

#include <iostream>
using namespace std;int mutex = 1;         //互斥信号量// mutex =1 代表进程空闲, mutex =0代表进程正在使用
int full;               //缓冲区非空个数
const int n = 10;      //缓冲区大小为 10
int empty = n;         //空缓冲区个数
char buffer[n];         //定义缓冲区
int pfull = 0;         //产品资源非空信号量//可用于多生产者时进行区分产品类不同对应的消费
int in = 0, out = 0;  //定义存取指针的初始位置// in 指定生产产品当前的位置, out 指定消费产品当前的位置
int choose = 1;            //选择,首次产生产品P //选择
void choice()
{cout << "按f或F继续,按q或Q退出程序:" << endl;cout << "--------------------------------------------" << endl;char ch;cin >> ch;if( ch == 'q' || ch == 'Q' ){mutex = 1;//把进程释放出来 exit( 0 );//退出}else if( ch == 'f' || ch == 'F' ){mutex = 1;//把进程释放出来cout << "输入选择继续:" << endl;cin >> choose;}else{cout << "输入非法!" << endl;choice(); //重新选择 }
}//显示缓冲区情况函数
void showbuffer( char a[10] )
{cout << "缓冲区存储情况为( ~ 为已消费资源):" ;for( int i = 0; i < 10; i ++ ){cout << a[i] << " ";//输出缓冲区情况 }cout << endl;
}///--------------------------------生产者--------------------------------------------------
//生产者类
class Producer
{private:int m_mutex;int m_full;int m_pfull;int m_in;public:Producer( int mu, int fu, int pfu, int pin ){m_mutex = mu;m_full = fu;m_pfull = pfu;m_in = in;}void showP(){if( mutex == 1 )//mutex = 1代表没有进程进行{if( full == n )//进程满了 {cout << "缓冲区空间已满!" << endl;exit( 0 );//退出 }mutex = 0;//mutex = 0代表有进程正在进行cout << "--------------------------------------------" << endl;cout << "生产者进程P:产生产品P" << endl;full++;//产品数量存储+1 pfull++;//生产者进程P生产数量while( buffer[in] == 'P' )//避免重复位置替换产品P {in = ( in + 1 ) % n;//循环队列计数 }buffer[ in ] = 'P';showbuffer( buffer );in = ( in + 1 ) % n;}else/// mutex = 0的情况 {cout << "进程P正在使用!" << endl;}choice();}
};///--------------------------------------消费者-------------------------------------------
//消费者类
class Consumer{private:int m_mutex;int m_full;int m_pfull;int m_out;char m_c;public:Consumer( int mu, int fu, int pfu, int ou, char c = '0' ){m_mutex = mu;m_full = fu;m_pfull = pfu;m_out = ou;m_c = c;}void showC( ){if( mutex == 1 )//mutex = 1代表没有进程进行{if( full == 0 ){cout << "没有进程可消费!" << endl;exit( 0 );}else{mutex = 0;if( pfull == 0 ){cout << " 消费者进程C没有可消费的!" << endl;exit( 0 );}else{cout << "--------------------------------------------" << endl;cout << "消费者进程C" << m_c << ":把产品P消费了->" << m_c << endl;full--;pfull--;buffer[ out ] = m_c;showbuffer( buffer );buffer[ out ] = '~';out = ( out + 1 ) % n;}}}else {cout << "进程C" << m_c << "正在使用!" << endl;}choice();
}
};//消费者类 1
class C1:public Consumer
{public:C1( int mu, int fu, int pfu, int ou, char c1 = '1' ):Consumer( mu, fu, pfu, ou, c1 ){} void showC1(){Consumer::showC();}
};//消费者类 2
class C2:public Consumer
{public:C2( int mu, int fu, int pfu, int ou, char c1 = '2' ):Consumer( mu, fu, pfu, ou, c1 ){} void showC2(){Consumer::showC();}
};//消费者类 3
class C3:public Consumer
{public:C3( int mu, int fu, int pfu, int ou, char c1 = '3' ):Consumer( mu, fu, pfu, ou, c1 ){} void showC3(){Consumer::showC();}
};int main()
{Producer p( mutex, full, pfull, in );Consumer c( mutex, full, pfull, out );C1 c1( mutex, full, pfull, out );C2 c2( mutex, full, pfull, out );C3 c3( mutex, full, pfull, out );while( choose != 0 ){switch( choose ){case 1:p.showP();break;case 2:c1.showC1();break;case 3:c2.showC2();break;case 4:c3.showC3();break;}}
}

六、运行结果

这里以缓冲区大小为 5 来测试

不同的消费者进程消费产品后转换成的结果不同

正常生产和消费,当生产者依次顺序占用缓冲区时,消费者也是依次顺序消费,当前队列到尽头时,采用循环继续,生产者在空缓冲区继续执行生产命令。

当缓冲区已满时,进程提示空间已满,程序正常状态退出!

当缓冲区没有产品时,消费者无法进行消费,此时进程提示没有进程可消费,程序正常状态退出!

更多测试结果请阅读者亲测~

七.结论

以上便是本次生产者与消费者问题的基本算法,生产者和消费者可以一对一、一对多或是多对多,只要分析清楚它们之间的同步互斥变量,共用的缓冲区资源的使用情况,解决好同步互斥问题,可以有效避免出现死锁的情况。通过生产者与消费者的问题算法,加深对信号量机制的理解和了解信号量的使用。

代码为原创,如有类似可联系了解情况,若有大神提出修改精进,欢迎评论区讨论!

生产者与消费者问题算法 C++(一对多)相关推荐

  1. 生产者和消费者模型(可以多对多,一对多、多对一、一对一)c++实现,没有使用pthread,时间片模拟并发

    生产者和消费者 nepu的恶臭作业 参考: link. link. #include <iostream> #include <time.h> #include <std ...

  2. 2.3.6 操作系统之进程同步与互斥经典问题(生产者-消费者问题、多生产者-多消费者问题、吸烟者问题、读者-写者问题、哲学家进餐问题)

    文章目录 0.前言 1.生产者-消费者问题 (1)问题描述 (2)问题分析 (3)如何实现? (4)实现互斥的P操作一定要在实现同步的P操作之后 (5)知识回顾与重要考点 2.多生产者-多消费者问题 ...

  3. 生产者和消费者代码———操作系统_操作系统基础15-生产者消费者问题

    在上一篇操作系统基础14提到通过信号量解决生产者消费者问题.本篇来详细说说操作系统中的经典问题-生成者消费者问题 生产者消费者问题 (Producer-consumer problem) 该问题是一个 ...

  4. 多生产者-多消费者问题

    文章目录 1 问题描述 2 问题分析 3 代码实现 4 分析总结 1 问题描述 桌子上有一只盘子,每次只能向其中放入一个水果.爸爸专向盘子中放苹果,妈妈专向盘子中放橘子,儿子专等着吃盘子中的橘子,女儿 ...

  5. Python爬虫的经典多线程方式,生产者与消费者模型

    在之前的文章当中我们曾经说道,在多线程并发的场景当中,如果我们需要感知线程之间的状态,交换线程之间的信息是一件非常复杂和困难的事情.因为我们没有更高级的系统权限,也没有上帝视角,很难知道目前运行的状态 ...

  6. Linux并发程序课程设计报告,网络操作系统课程设计--进程机制与并发程序设计-linux下生产者与消费者的问题实现.doc...

    网 络 操 作 系 统 课 程 设 计 网络操作系统课程设计 设计内容:进程机制与并发程序设计inux下生产者与消费者的问题实现进程机制与并发程序设计inux下生产者与消费者的问题实现 (1)掌握基本 ...

  7. 作为程序猿必须了解的生产者与消费者

    JUC并发编程三:生产者与消费者(Java) 面试:单例模式,排序算法,生产者与消费者,死锁 代码示例: package PC;/* 线程之间的通信问题:生产者与消费者问题! 等待唤醒,通知唤醒 线程 ...

  8. 生产者和消费者问题详解

    定义 生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例.该问题描述了 ...

  9. 深入分析Kafka生产者和消费者

    深入Kafka生产者和消费者 Kafka生产者 消息发送的流程 发送方式 发送并忘记 同步发送 异步发送 生产者属性配置 序列化器 分区器 自定义分区器 Kafka消费者 消费者属性配置 消费者基础概 ...

最新文章

  1. Android Volley入门到精通:初识Volley的基本用法
  2. pytorch的梯度计算以及backward方法
  3. linux so_nosigpipe,TCP_NODELAY/SO_LINGER/SO_NOSIGPIPE/MSG_NOSIGNAL设置
  4. linux无filelength函数,Linux Shell 自定义函数(定义、返回值、变量作用域)介绍
  5. 谷歌回归中国,最紧张的为什么会是小米、华为们?
  6. IE浏览器网页无法缩放怎么办 解决IE浏览器网页无法缩放的方法
  7. PostgreSQL进程结构
  8. Bzoj 4147: [AMPPZ2014]Euclidean Nim(博弈)
  9. Spark UI无法查看到slave节点
  10. mysql 清空或删除表数据后,控制表自增列值的方法
  11. go和python组合开发_Go+Python双语言混合开发
  12. linux内核之同步
  13. Win7免费升级Win10
  14. java有哪些技术领域
  15. CentOS7 安装 YApi
  16. 斯帅变阵只为讨好皇帝 36岁高龄大Z成热火首发
  17. Modularity(模块化)
  18. 如何保障业务0暂停下,从11gR2 MAA升级到12c?
  19. 玉米社:竞价推广的常见误区有哪些?
  20. 大纵深战役理论和闪电战理论

热门文章

  1. 浅议.NET遗留应用改造
  2. 什么是垂直搜索引擎?
  3. 优酷网页player使用-替换视频ID即可
  4. LKA-车道保持辅助系统
  5. 金融帝国实验室(Capitalism Lab)官方认证汉化包下载(V3.07)
  6. 『金融帝国实验室』(Capitalism Lab)〔房地产DLC〕最新开发动态(2022.09.04)
  7. 1635_fileno的简单使用
  8. python之pdb调试
  9. MacPro微信可以使用,其他应用均不能联网,浏览器网页也打不开
  10. 浪擎终端备份系统2008 完善的桌面备份方案