赞
踩
目录
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
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
- //生产者类
- 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();
- }
- };

- //消费者类 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;
- }
- }
- }

- #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 来测试
不同的消费者进程消费产品后转换成的结果不同
正常生产和消费,当生产者依次顺序占用缓冲区时,消费者也是依次顺序消费,当前队列到尽头时,采用循环继续,生产者在空缓冲区继续执行生产命令。
当缓冲区已满时,进程提示空间已满,程序正常状态退出!
当缓冲区没有产品时,消费者无法进行消费,此时进程提示没有进程可消费,程序正常状态退出!
更多测试结果请阅读者亲测~
以上便是本次生产者与消费者问题的基本算法,生产者和消费者可以一对一、一对多或是多对多,只要分析清楚它们之间的同步互斥变量,共用的缓冲区资源的使用情况,解决好同步互斥问题,可以有效避免出现死锁的情况。通过生产者与消费者的问题算法,加深对信号量机制的理解和了解信号量的使用。
代码为原创,如有类似可联系了解情况,若有大神提出修改精进,欢迎评论区讨论!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。