当前位置:   article > 正文

生产者与消费者问题算法 C++(一对多)_生产者消费者问题c++代码

生产者消费者问题c++代码

目录

文章目录

前言

一、实验内容

二、背景知识

三、思路

四、核心代码

1.生产者类

2.1 消费者子类1

2.2 消费者子类2

2.3 消费者子类3

3.主函数

五、源代码

六、运行结果

​编辑

七.结论


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

前言

一、实验内容

1.问题描述

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

2.功能要求

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

二、背景知识

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

三、思路

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

四、核心代码

数据说明

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

1.生产者类

  1. //生产者类
  2. class Producer
  3. {
  4. private:
  5. int m_mutex;
  6. int m_full;
  7. int m_pfull;
  8. int m_in;
  9. public:
  10. Producer( int mu, int fu, int pfu, int pin )
  11. {
  12. m_mutex = mu;
  13. m_full = fu;
  14. m_pfull = pfu;
  15. m_in = in;
  16. }
  17. void showP()
  18. {
  19. if( mutex == 1 )//mutex = 1代表没有进程进行
  20. {
  21. if( full == n )//进程满了
  22. {
  23. cout << "缓冲区空间已满!" << endl;
  24. exit( 0 );//退出
  25. }
  26. mutex = 0;//mutex = 0代表有进程正在进行
  27. cout << "--------------------------------------------" << endl;
  28. cout << "生产者进程P:产生产品P" << endl;
  29. full++;//产品数量存储+1
  30. pfull++;//生产者进程P生产数量
  31. while( buffer[in] == 'P' )//避免重复位置替换产品P
  32. {
  33. in = ( in + 1 ) % n;//循环队列计数
  34. }
  35. buffer[ in ] = 'P';
  36. showbuffer( buffer );
  37. in = ( in + 1 ) % n;
  38. }
  39. else/// mutex = 0的情况
  40. {
  41. cout << "进程P正在使用!" << endl;
  42. }
  43. choice();
  44. }
  45. };

2.消费者类

  1. //消费者类
  2. class Consumer{
  3. private:
  4. int m_mutex;
  5. int m_full;
  6. int m_pfull;
  7. int m_out;
  8. char m_c;
  9. public:
  10. Consumer( int mu, int fu, int pfu, int ou, char c = '0' )
  11. {
  12. m_mutex = mu;
  13. m_full = fu;
  14. m_pfull = pfu;
  15. m_out = ou;
  16. m_c = c;
  17. }
  18. void showC( )
  19. {
  20. if( mutex == 1 )//mutex = 1代表没有进程进行
  21. {
  22. if( full == 0 )
  23. {
  24. cout << "没有进程可消费!" << endl;
  25. exit( 0 );
  26. }
  27. else{
  28. mutex = 0;
  29. if( pfull == 0 )
  30. {
  31. cout << " 消费者进程C没有可消费的!" << endl;
  32. exit( 0 );
  33. }
  34. else
  35. {
  36. cout << "--------------------------------------------" << endl;
  37. cout << "消费者进程C" << m_c << ":把产品P消费了->" << m_c << endl;
  38. full--;
  39. pfull--;
  40. buffer[ out ] = m_c;
  41. showbuffer( buffer );
  42. buffer[ out ] = '~';
  43. out = ( out + 1 ) % n;
  44. }
  45. }
  46. }
  47. else
  48. {
  49. cout << "进程C" << m_c << "正在使用!" << endl;
  50. }
  51. choice();
  52. }
  53. };

2.1 消费者子类1

  1. //消费者类 1
  2. class C1:public Consumer
  3. {
  4. public:
  5. C1( int mu, int fu, int pfu, int ou, char c1 = '1' ):Consumer( mu, fu, pfu, ou, c1 )
  6. {}
  7. void showC1()
  8. {
  9. Consumer::showC();
  10. }
  11. };

2.2 消费者子类2

  1. //消费者类 2
  2. class C2:public Consumer
  3. {
  4. public:
  5. C2( int mu, int fu, int pfu, int ou, char c1 = '2' ):Consumer( mu, fu, pfu, ou, c1 )
  6. {}
  7. void showC2()
  8. {
  9. Consumer::showC();
  10. }
  11. };

2.3 消费者子类3

  1. //消费者类 3
  2. class C3:public Consumer
  3. {
  4. public:
  5. C3( int mu, int fu, int pfu, int ou, char c1 = '3' ):Consumer( mu, fu, pfu, ou, c1 )
  6. {}
  7. void showC3()
  8. {
  9. Consumer::showC();
  10. }
  11. };

3.主函数

  1. int main()
  2. {
  3. Producer p( mutex, full, pfull, in );
  4. Consumer c( mutex, full, pfull, out );
  5. C1 c1( mutex, full, pfull, out );
  6. C2 c2( mutex, full, pfull, out );
  7. C3 c3( mutex, full, pfull, out );
  8. while( choose != 0 )
  9. {
  10. switch( choose )
  11. {
  12. case 1:
  13. p.showP();
  14. break;
  15. case 2:
  16. c1.showC1();
  17. break;
  18. case 3:
  19. c2.showC2();
  20. break;
  21. case 4:
  22. c3.showC3();
  23. break;
  24. }
  25. }
  26. }

五、源代码

  1. #include <iostream>
  2. using namespace std;
  3. int mutex = 1; //互斥信号量
  4. // mutex =1 代表进程空闲, mutex =0代表进程正在使用
  5. int full; //缓冲区非空个数
  6. const int n = 10; //缓冲区大小为 10
  7. int empty = n; //空缓冲区个数
  8. char buffer[n]; //定义缓冲区
  9. int pfull = 0; //产品资源非空信号量
  10. //可用于多生产者时进行区分产品类不同对应的消费
  11. int in = 0, out = 0; //定义存取指针的初始位置
  12. // in 指定生产产品当前的位置, out 指定消费产品当前的位置
  13. int choose = 1; //选择,首次产生产品P
  14. //选择
  15. void choice()
  16. {
  17. cout << "按f或F继续,按q或Q退出程序:" << endl;
  18. cout << "--------------------------------------------" << endl;
  19. char ch;
  20. cin >> ch;
  21. if( ch == 'q' || ch == 'Q' )
  22. {
  23. mutex = 1;//把进程释放出来
  24. exit( 0 );//退出
  25. }
  26. else if( ch == 'f' || ch == 'F' )
  27. {
  28. mutex = 1;//把进程释放出来
  29. cout << "输入选择继续:" << endl;
  30. cin >> choose;
  31. }
  32. else
  33. {
  34. cout << "输入非法!" << endl;
  35. choice(); //重新选择
  36. }
  37. }
  38. //显示缓冲区情况函数
  39. void showbuffer( char a[10] )
  40. {
  41. cout << "缓冲区存储情况为( ~ 为已消费资源):" ;
  42. for( int i = 0; i < 10; i ++ )
  43. {
  44. cout << a[i] << " ";//输出缓冲区情况
  45. }
  46. cout << endl;
  47. }
  48. ///--------------------------------生产者--------------------------------------------------
  49. //生产者类
  50. class Producer
  51. {
  52. private:
  53. int m_mutex;
  54. int m_full;
  55. int m_pfull;
  56. int m_in;
  57. public:
  58. Producer( int mu, int fu, int pfu, int pin )
  59. {
  60. m_mutex = mu;
  61. m_full = fu;
  62. m_pfull = pfu;
  63. m_in = in;
  64. }
  65. void showP()
  66. {
  67. if( mutex == 1 )//mutex = 1代表没有进程进行
  68. {
  69. if( full == n )//进程满了
  70. {
  71. cout << "缓冲区空间已满!" << endl;
  72. exit( 0 );//退出
  73. }
  74. mutex = 0;//mutex = 0代表有进程正在进行
  75. cout << "--------------------------------------------" << endl;
  76. cout << "生产者进程P:产生产品P" << endl;
  77. full++;//产品数量存储+1
  78. pfull++;//生产者进程P生产数量
  79. while( buffer[in] == 'P' )//避免重复位置替换产品P
  80. {
  81. in = ( in + 1 ) % n;//循环队列计数
  82. }
  83. buffer[ in ] = 'P';
  84. showbuffer( buffer );
  85. in = ( in + 1 ) % n;
  86. }
  87. else/// mutex = 0的情况
  88. {
  89. cout << "进程P正在使用!" << endl;
  90. }
  91. choice();
  92. }
  93. };
  94. ///--------------------------------------消费者-------------------------------------------
  95. //消费者类
  96. class Consumer{
  97. private:
  98. int m_mutex;
  99. int m_full;
  100. int m_pfull;
  101. int m_out;
  102. char m_c;
  103. public:
  104. Consumer( int mu, int fu, int pfu, int ou, char c = '0' )
  105. {
  106. m_mutex = mu;
  107. m_full = fu;
  108. m_pfull = pfu;
  109. m_out = ou;
  110. m_c = c;
  111. }
  112. void showC( )
  113. {
  114. if( mutex == 1 )//mutex = 1代表没有进程进行
  115. {
  116. if( full == 0 )
  117. {
  118. cout << "没有进程可消费!" << endl;
  119. exit( 0 );
  120. }
  121. else{
  122. mutex = 0;
  123. if( pfull == 0 )
  124. {
  125. cout << " 消费者进程C没有可消费的!" << endl;
  126. exit( 0 );
  127. }
  128. else
  129. {
  130. cout << "--------------------------------------------" << endl;
  131. cout << "消费者进程C" << m_c << ":把产品P消费了->" << m_c << endl;
  132. full--;
  133. pfull--;
  134. buffer[ out ] = m_c;
  135. showbuffer( buffer );
  136. buffer[ out ] = '~';
  137. out = ( out + 1 ) % n;
  138. }
  139. }
  140. }
  141. else
  142. {
  143. cout << "进程C" << m_c << "正在使用!" << endl;
  144. }
  145. choice();
  146. }
  147. };
  148. //消费者类 1
  149. class C1:public Consumer
  150. {
  151. public:
  152. C1( int mu, int fu, int pfu, int ou, char c1 = '1' ):Consumer( mu, fu, pfu, ou, c1 )
  153. {}
  154. void showC1()
  155. {
  156. Consumer::showC();
  157. }
  158. };
  159. //消费者类 2
  160. class C2:public Consumer
  161. {
  162. public:
  163. C2( int mu, int fu, int pfu, int ou, char c1 = '2' ):Consumer( mu, fu, pfu, ou, c1 )
  164. {}
  165. void showC2()
  166. {
  167. Consumer::showC();
  168. }
  169. };
  170. //消费者类 3
  171. class C3:public Consumer
  172. {
  173. public:
  174. C3( int mu, int fu, int pfu, int ou, char c1 = '3' ):Consumer( mu, fu, pfu, ou, c1 )
  175. {}
  176. void showC3()
  177. {
  178. Consumer::showC();
  179. }
  180. };
  181. int main()
  182. {
  183. Producer p( mutex, full, pfull, in );
  184. Consumer c( mutex, full, pfull, out );
  185. C1 c1( mutex, full, pfull, out );
  186. C2 c2( mutex, full, pfull, out );
  187. C3 c3( mutex, full, pfull, out );
  188. while( choose != 0 )
  189. {
  190. switch( choose )
  191. {
  192. case 1:
  193. p.showP();
  194. break;
  195. case 2:
  196. c1.showC1();
  197. break;
  198. case 3:
  199. c2.showC2();
  200. break;
  201. case 4:
  202. c3.showC3();
  203. break;
  204. }
  205. }
  206. }

六、运行结果

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

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

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

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

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

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

七.结论

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/267910
推荐阅读
相关标签
  

闽ICP备14008679号