实验目的
- 掌握进程、线程的概念,熟悉相关的控制语;
- 掌握进程、线程间的同步原理和方法;
- 掌握进程、线程间的互斥原理和方法;
- 掌握使用信号量原语解决进程、线程间互斥和同步方法。
实验思路
生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。
与此同时,消费者也在缓冲区消耗这些数据。
该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
为使生产者进程与消费者进程能并发执行,在两者之间设置了一个具有 n 个缓冲区的缓冲池:生产者进程从文件中读取一个数据,并将它存放到一个缓冲区中;消费者进程从一个缓冲区中取走数据,并输出此数据。生产者和消费者之间必须保持同步原则:不允许消费者进程到一个空缓冲区去取产品;也不允许生产者进程向一个已装满产品且尚未被取走的缓冲区中投放产品。
实现一个生产者对多个消费者,每一次生成数随机,若为奇数为生产者生产,反之为消费者消费,因此过程中会有消费者多次消费,是1对N的。
实验过程与内容
1设置一个生产者、消费者类,成员为以下
int in,out;//指向有产品的下标的指针
int count;//缓冲区的产品数
int buffer[N];//缓冲区,其中N为缓冲区的大小
int mutex;//互斥信号量
int empty,full;//判断缓冲区是否为空或者满,信号量
2实现PV操作
void Wait(int &s){//P操作
if(s<=0) return ;
s--;
}
void Signal(int &s){//V操作
s++;
}
3生产者生产
void Producer(){
if(empty==0){
full=1;
cout<<"产品已满,不能再生产"<<endl;
return ;
}
Wait(empty);//empty--;
buffer[out]=1; //生产一个产品
out=(out+1)%N; //尾指针后移一位,构成循环队列
cout<<"生产者生产了一个产品"<<endl;
/*对count互斥访问*/
Wait(mutex);
count++;
Signal(mutex);
}
4消费者消费
void Consumer(){
if(empty==N){
cout<<"没有产品,不能消费"<<endl;//每次消费之前判断当前缓冲池有无商品
return ;
}
buffer[in]=0;//消费一个产品
in=(in+1)%N;//头指针后移一位,构成循环队列
cout<<"消费者消费了一个产品"<<endl;
/*对count互斥访问*/
Wait(mutex);
count--;
Signal(mutex);
if(empty<=N){
full=0;
Signal(empty);//empty++;
}
}
5显示缓冲区的情况
void Display(){
for(int i=0;i<N;i++)
cout<<buffer[i];
cout<<endl<<"一共有"<<count<<"个产品"<<endl<<endl;
}
结果展示
为方便展示,缓冲区设置为10,只进行50次生产和消费,可以修改代码,增加缓冲区容量和增加生产者消费者的操作次数。
结论
缓冲区是临界资源,各进程必须互斥地访问,为了避免两个进程之间相互干扰,我们利用信号量机制来实现进程间互斥和同步 ,使用数组模拟的循环队列来完成缓冲区。
生产者进程向缓冲区投入产品,则count加一;消费者进程向缓冲区取出产品,则count减一
完整代码
#include <iostream>//一个生产者,多个消费者,因为生成数随机,会有消费者多次消费
//会在每次消费之前判断当前缓冲池有无商品
#include <time.h>//生成数随机,消费者、生产者生产和消费随机
#include <stdlib.h>
#define N 10 //产品数量,可以改
using namespace std;
/*生产者消费者类*/
class PandC{
private:
int in,out;//指向有产品的下标的指针
int count;//缓冲区的产品数
int buffer[N];//缓冲区,其中N为缓冲区的大小
int mutex;//互斥信号量
int empty,full;//判断缓冲区是否为空或者满,信号量
public:
/*初始化,构造生产者消费者*/
PandC(){
in=0;out=0;count=0;
empty=N;full=0;mutex=1;
for(int i=0;i<N;i++)
buffer[i]=0;
}
/*生产者生产*/
void Producer(){
if(empty==0){
full=1;
cout<<"产品已满,不能再生产"<<endl;
return ;
}
Wait(empty);//empty--;
buffer[out]=1; //生产一个产品
out=(out+1)%N; //尾指针后移一位,构成循环队列
cout<<"生产者生产了一个产品"<<endl;
/*对count互斥访问*/
Wait(mutex);
count++;
Signal(mutex);
}
/*消费者消费*/
void Consumer(){
if(empty==N){
cout<<"没有产品,不能消费"<<endl;//每次消费之前判断当前缓冲池有无商品
return ;
}
buffer[in]=0;//消费一个产品
in=(in+1)%N;//头指针后移一位,构成循环队列
cout<<"消费者消费了一个产品"<<endl;
/*对count互斥访问*/
Wait(mutex);
count--;
Signal(mutex);
if(empty<=N){
full=0;
Signal(empty);//empty++;
}
}
/*显示现在缓冲区的情况*/
void Display(){
for(int i=0;i<N;i++)
cout<<buffer[i];
cout<<endl<<"一共有"<<count<<"个产品"<<endl<<endl;
}
void Wait(int &s){
if(s<=0) return ;
s--;
}
void Signal(int &s){
s++;
}
};
int main(){
int i=0;
srand(time(NULL));
PandC x;
/*随机执行生产者生产还是消费者消费*/
cout<<"初始状态"<<endl;x.Display();
do{
if(rand()&1)//利用比例控制生产速度,如果为奇数,为生产者生产
x.Producer();
else//否则为消费者消费
x.Consumer();
x.Display();
i++;
}while(i!=50);//(方便展示,只实现50次,可以修改次数)
return 0;
}