资源描述
(操作系统课程设计)
生
产
者
与
消
费
者
学生姓名:
学生学号:
班 级:
0311401、02、03、04班制
二〇一三年十二月
一、 课程题目分析
这个题目就是生产者向消费者提供商品,消费者消耗商品,并且两组人共用同一缓冲区。生产者提供了商品之后消费者才能去取商品,消费者若不取走商品则当缓冲区用完之后生产者则不能再向缓冲区中添加新得商品。
思考问题:
(1) 对于生产者进程:每产生一个数据,则需去访问共用缓冲区就是否有已满,未满则可以将该数据存入并通知消费者进程,否则不能。
(2) 对于消费者进程:每当想去消费(取出数据)时,则需访问缓冲区就是否为空,为空则不能消费(取出数据),否则可以取,并通知生产者。
(3) 缓冲区就是个临界资源,所有得进程对于该空间都就是共享得,所以,还有互斥问题存在。
二、 课程设计目得
通过实验模拟生产者与消费者之间得关系,了解并掌握她们之间得关系及原理。由此增加对进程同步问题得了解:
(1) 掌握基本得同步互斥算法,理解生产者与消费者模型
(2) 了解windows中多线程(多进程)得并发执行机制,线程(进程)间得同步于互斥
(3) 学习使用windows中基本得同步对象,掌握相应得API。
三、 课程设计内容
有n个生产者与m个消费者,连接在具有k个单位缓冲区得有界环转缓冲上,故又称有界缓冲问题。其中Pi与Cj都就是并发进程,只要缓冲区未满,生产者进程Pi所生产得产品就可投入缓冲区;类似地,只要缓冲区非空,消费者进程Cj就可以从缓冲区取走并消耗产品。
四、 开发环境
操作系统:Windows系统
编写语言:C++语言
五、 系统分析设计
(一) 算法原理
生产者——消费者问题就是典型得进程同步问题,这些进程必须按照一定得生产率与消费率来访问共享缓冲区,用P、V操作解决生产者与消费者共享单缓冲区得问题,可设置两个信号量empty与full,其初值分别为1与0,empty指示能否向缓冲区放入产品,full指示能否从缓冲区取出产品。为了使其协调工作,必须使用一个信号量mutex(初值为1),以限制生产者与消费者互斥地对缓冲区进行存取,另用两个信号量empty1(初值为缓冲区大小)与full1(初值为0),以保证生产者不向已满得缓冲区中放入产品,消费者不从空缓冲区中取产品。
(二) 功能描述
生产者功能描述:在同一个进程地址空间内执行两个线程。生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。
消费者功能描述:消费者线程从缓冲区获得物品,然后释放缓冲区,当消费者线程消费物品时,如果没有满得缓冲区,那么消费者线程将被阻塞,直到新得物品被生产出来。
(三) 算法流程图
生产者流程图: 消费者流程图:
总得流程图:
(四) 数据结构及部分函数描述
(1)类SeqSquare:对类SeqSquare得声明及其中一些函数
class SeqSquare
{
public:
ﻩSeqSquare(int n);
~SeqSquare();
void P(int x); //p操作
ﻩvoid V(int x); //v操作
bool IsEmpty(); //判断就是否为空
ﻩbool IsFull(); //判断就是否已满
ﻩvoid deca();
void decb();
ﻩint getSize();
ﻩint getmaxSize();
ﻩint gettop();
ﻩint geta();
int getb();
protected:
private:
ﻩint *elements;
int top,a,b,maxSize;
};
说明:①用动态整型数组*elements来代表缓冲区,不管就是生产产品还就是对已有产品得消费都需要访问该缓冲区。②函数IsFull()用于判断缓冲区就是否已满,生产者能否使用缓冲区.③函数IsEmpty()用于判断缓冲区就是否为空,消费者能否使用缓冲区。
(2) 生产者与消费者操作及显示函数showbuf:
void producer(SeqSquare *a) //生产者操作
{
ﻩa->P(1);
}
void consumer(SeqSquare *a) //消费者操作
{
ﻩa—〉V(1);
}
//缓冲区显示
void showbuf(SeqSquare *a)
{
int i=a—>getSize();
}
(3) 在实现本程序得生产者消费者模型时,具体地通过以下同步对象实现互斥:
①设一个互斥量Mutex,以实现生产者在查询与保留缓冲区得下一个空位置时进行互斥。
②每一个生产者用一个信号量与消费者同步,通过设置Full实现,该组信号量用于表示相应产品以生产。同时用一个表示空缓冲区数目得信号量Empty进行类似得同步,指示缓冲区中就是否存在空位置,以便开始生产下一个产品。
(四) 调试过程
为解决生产者、消费者问题,应该设置两个资源信号量,其中一个表示空缓冲区得数目,用Full表示,其初值为用户输入得缓冲区得大小,另一个表示缓冲区中产品得数目,用Empty表示,其初值为0、另外,由于缓冲区就是一个临界资源,必须互斥使用,所以还需要再设置一个互斥信号量Mutex,其初值为1、
在生产者、消费者问题中,信号量实现两种功能。首先,她就是生产产品与消费产品得计数器,计数器得初值就是可使用得资源数目(缓冲区得长度)。其次,她就是确保产品得生产者与消费者之间得动作同步得同步器。
生产者要生产一个产品时,首先对资源信号量Full与互斥信号量Mutex进行P操作,申请资源.如果可以通过得话,就生产一个产品,并把产品送人缓冲区.然后对互斥信号量Mutex与资源信号量Empty进行V操作,释放资源。
消费者要消费一个产品时,首先对资源信号量Empty与互斥信号量Mutex进行P操作,申请资源。如果可以通过得话就从缓冲区取出一个产品并消费掉.然后对互斥信号量Mutex与资源信号量Full进行V操作,释放资源。
如果缓冲区中已经没有可用资源,就把申请资源得进程添加到等待队列得队尾.如果有一个资源被释放,在等待队列中得第一个进程被唤醒并取得这个资源得使用权。
(五) 参考资料
《操作系统教程》 孙钟秀 高等教育出版社
《C++程序设计》 谭浩强 高等教育出版社
六、 运行实例及结果分析
(一) 运行实例
缓冲区大小为3,先生产一件产品,显示缓冲区,再接着生产一件产品,消耗一件产品,显示缓冲区,在消耗两件产品,再生产4件产品,改变缓冲区得大小为6,显示缓冲区,选择一个未出现得选项,退出程序.
(二) 结果显示
(三) 结果分析
(1) 在每个程序中需要先做P,后做V,二者要成对出现,夹在二者中间得代码段就就是该进程得临界区。
(2) 对同步信号量full与empty得P,V操作同样必须成对出现,但它们分别位于不同得程序中。
(3)无论在生产者进程中还就是消费者进程中,两个P操作得次序不能颠倒:应先执行同步信号量得P操作,然后执行互斥信号量得P操作.否则可能造成进程死锁。
七、个人体验
虽然我也很想用java语言写这个程序,但就是由于自己学艺不精,所以只能用C++写。通过这个实验我发现我以前有很多知识都忘记了,重新拿起课本学习时发现原来很多不懂得问题都有了新得认识,有一种豁然开朗得感觉。也为我考研开了一个好得开头。
我认为我完成得这个设计做得比较出色得地方就是对C++语言中类以及数组得运用,其实这里我对数组得操作就是按照“先进先出”得方法进行运作得,这就是参考了栈得工作原理,因为缓冲区一般也就是堆栈,比较符合设计要求。
这次实验中我感觉做得很粗糙,自己所想得模拟过程得确得到实现了,但就是感觉灵活性不太高,思考还不过全面,应该以后多注意一下,多考虑考虑才就是。
在这次实验中我重新将《C++程序设计》与《数据结构》得几个重要章节复习了一遍,对类、数组、C++得I/O流类库以及堆栈得语句格式、注意细节都再一次熟悉,感觉蛮有趣得.不过,在编程过程中许多语句得小问题还真就是出现不少,而且感觉自己对C++强大丰富得语句方法用得太呆板,不够灵活,总就是想到那些常用得,而忽略了颗粒让语句更简短得方法,以后要多多注意才就是.
八、 附录
// 生产者消费者1、cpp : Defines the entry point for the console application、
//
#include "stdafx、h”
#include ”iostream”
using namespace std;
class SeqSquare
{
public:
SeqSquare(int n);
~SeqSquare();
ﻩvoid P(int x); //p操作
void V(int x); //v操作
ﻩbool IsEmpty(); //判断就是否为空
ﻩbool IsFull(); //判断就是否已满
ﻩvoid deca();
ﻩvoid decb();
ﻩint getSize();
int getmaxSize();
ﻩint gettop();
ﻩint geta();
int getb();
protected:
private:
int *elements;
int top,a,b,maxSize;
};
bool SeqSquare::IsEmpty() //判断就是否为空
{
ﻩreturn(top==—1)?true:false;
}
bool SeqSquare::IsFull() //判断就是否已满
{
return(top>=maxSize-1)?true:false;
}
void SeqSquare::deca()
{
a——;
}
void SeqSquare::decb()
{
ﻩb-—;
}
int SeqSquare::getSize()
{
ﻩreturn top+1;
}
int SeqSquare::getmaxSize()
{
return maxSize;
}
int SeqSquare::gettop()
{
return top;
}
int SeqSquare::geta()
{
return a;
}
int SeqSquare::getb()
{
ﻩreturn b;
}
SeqSquare::SeqSquare(int n)
{
ﻩtop =-1;
ﻩa = b =0;
maxSize = n;
ﻩelements = new int[maxSize];
}
void SeqSquare::P(int x)
{
if(IsFull()==true)
ﻩ{
ﻩﻩa=a+1;
}
else
{
elements[++top] = x;
}
}
void SeqSquare::V(int x)
{
ﻩif(IsEmpty()==true)
ﻩ{
ﻩ b = b+1;
ﻩ}
ﻩelse
{
ﻩx = elements[top—-];
ﻩ}
}
void producer(SeqSquare *a) //生产者操作
{
a->P(1);
}
void consumer(SeqSquare *a) //消费者操作
{
ﻩa->V(1);
}
SeqSquare::~SeqSquare()
{
delete elements;
}
//缓冲区显示
void showbuf(SeqSquare *a)
{
ﻩint i=a—>getSize();
}
int main()
{
ﻩint i,n;
cout<〈"请输入缓冲区大小:”<<endl;
cin>〉n;
SeqSquare *s;
s = new SeqSquare(n);
ﻩwhile(i!=4)
{
cout<<"请选择操作: "<<endl;
cout<〈"1、生产一件产品;2、消费一件产品”〈<endl;
cout〈<”3、显示缓冲区; 4、退出系统. "〈〈endl;
ﻩcout<<"5、需要改变缓冲区大小! ”<<endl;
ﻩcin>〉i;
ﻩswitch(i)
ﻩ {
ﻩ case 1:
ﻩ producer(s);
ﻩﻩ if (s->geta()==0)
ﻩﻩﻩ{
ﻩ cout<〈endl<〈"成功生产一件商品!”<<endl〈〈endl;
ﻩﻩ }
ﻩ else
ﻩ {
ﻩﻩcout<〈endl<〈”没有空间供生产者生产!"<<endl〈<endl;
ﻩﻩ s->deca();
ﻩ }
ﻩﻩ break;
ﻩﻩcase 2:
ﻩconsumer(s);
ﻩif (s-〉getb()==0)
{
ﻩﻩﻩ cout〈<endl〈〈"成功消费一件商品!"<<endl〈<endl;
ﻩﻩﻩﻩ}
ﻩ else
{
ﻩﻩ cout〈〈endl<<"没有产品供消费者消费!"<〈endl〈<endl;
}
ﻩ ﻩbreak;
ﻩcase 3:
showbuf(s);
ﻩﻩ cout〈<endl〈<"缓冲区已占用:"〈<s-〉getSize()<<" "〈<"可用空间为:"<〈(n—s—>getSize())〈<endl〈〈endl;
ﻩﻩbreak;
ﻩ case 4:
ﻩ cout〈<endl〈〈”成功退出程序!”<<endl<〈endl;
break;
ﻩﻩcase 5:
cout<〈endl<〈"请输入缓冲区大小:"<<endl;
ﻩﻩcin>〉n;
ﻩﻩ s = new SeqSquare(n);
ﻩﻩ cout〈〈endl<<”缓冲区大小已发生改变,数据已清除!”〈〈endl<〈endl;
ﻩﻩbreak;
ﻩdefault:
ﻩ ﻩcout<<endl〈<"输入操作不正确,请重新输入!"<〈endl<<endl;
ﻩ}
ﻩ}
return 0;
}
展开阅读全文