生产者与消费者的问题操作系统课程设计.docx
《生产者与消费者的问题操作系统课程设计.docx》由会员分享,可在线阅读,更多相关《生产者与消费者的问题操作系统课程设计.docx(12页珍藏版)》请在冰点文库上搜索。
生产者与消费者的问题操作系统课程设计
生产者与消费者的问题-----操作系统课程设计
———————————————————————————————— 作者:
————————————————————————————————日期:
ﻩ
闽江学院
计算机系
网络操作系统课程设计
设计内容:
进程机制与并发程序设计——linux下生产者与消费者的问题实现
目录:
一、设计内容····························3
二、设计思想····························4
三、系统结构····························5
四、PV操作代码··························5
五、C++程序代码·························6
六、运行结果截图························9
七、参考文献····························11
八、实验总结····························11
一、设计内容
进程机制与并发程序设计————linux下生产者与消费者的问题实现
1.实验目的
(1)掌握基本的同步互斥算法,理解生产者和消费者同步的问题模型。
(2)了解linux中多线程的并发执行机制,线程间的同步和互斥。
2、实验环境:
C/C++语言编译器
3、实验要求
(1)创建生产者和消费者线程
在linux环境下,创建一个控制台进程,在此进程中创建n个线程来模拟生产者或者消费者。
这些线程的信息由本程序定义的“测试用例文件”中予以指定。
该文件的格式和含义如下:
3
1P 3
2 P 4
3C 41
4P 2
5C 31 2 4
第一行说明程序中设置几个临界区,其余每行分别描述了一个生产者或者消费者线程的信息。
每一行的各字段间用Tab键隔开。
不管是消费者还是生产者,都有一个对应的线程号,即每一行开始字段那个整数。
第二个字段用字母P或者C区分是生产者还是消费者。
第三个字段表示在进入相应线程后,在进行生产和消费动作前的休眠时间,以秒计时;这样做的目的是可以通过调整这一列参数,控制开始进行生产和消费动作的时间。
如果是代表生产者,则该行只有三个字段。
如果代表消费者,则该行后边还有若干字段,代表要求消费的产品所对应的生产者的线程号。
所以务必确认这些对应的线程号存在并且该线程代表一个生产者。
(2)生产和消费的规则
在按照上述要求创建线程进行相应的读写操作时,还需要符合以下要求:
①共享缓冲区存在空闲空间时,生产者即可使用共享缓冲区。
②从上边的测试数据文件例子可以看出,某一生产者生产一个产品后,可能不止一个消费者,或者一个消费者多次地请求消费该产品。
此时,只有当所有的消费需求都被满足以后,该产品所在的共享缓冲区才可以被释放,并作为空闲空间允许新的生产者使用。
③每个消费者线程的各个消费需求之间存在先后顺序。
例上述测试用例文件包含一行信息“5C3l24”,可知这代表一个消费者线程,该线程请求消费1,2,4号生产者线程生产的产品。
而这种消费是有严格顺序的,消费1号线程产品的请求得到满足后才能继续往下请求2号生产者线程的产品。
④要求在每个线程发出读写操作申请、开始读写操作和结束读写操作时分别显示提示信息。
(3)相关基础知识
本实验所使用的生产者和消费者模型具有如下特点:
本实验的多个缓冲区不是环形循环的,也不要求按顺序访问。
生产者可以把产品放到目前某一个空缓冲区中。
消费者只消费指定生产者的产品。
在测试用例文件中指定了所有的生产和消费的需求,只有当共享缓冲区的数据满足了所有关于它的消费需求后,此共享缓冲区才可以作为空闲空间允许新的生产者使用。
本实验在为生产者分配缓冲区时各生产者间必须互斥,此后各个生产者的具体生产活动可以并发。
而消费者之间只有在对同一产品进行消费时才需要互斥,同时它们在消费过程结束时需要判断该消费对象是否已经消费完毕并清除该产品。
linux用来实现同步和互斥的实体。
在linux中,常见的同步对象有:
信号量(Semaphore)、互斥量(Mutex)、临界段(CriticalSection)等。
使用这些对象都分为三个步骤,一是创建或者初始化:
接着请求该同步对象,随即进入临界区,这一步对应于互斥量的上锁;最后释放该同步对象,这对应于互斥量的解锁。
这些同步对象在一个线程中创建,在其他线程中都可以使用,从而实现同步互斥。
二、设计思想
生产者进程与消费者进程是经典的同步互斥关系。
系统创建两类进程:
proceducer()和consumer(),分别用来描述生产者和消费者的行为。
生产者与消费者问题是指若干进程通过循环缓冲池区交换数据。
如下图所示,生产者进程不断向循环缓冲池区中写入数据(即生产数据),而消费者进程不断从循环缓冲池区中读出数据(即消费数据)。
循环缓冲池共有N个缓冲区,缓冲区可以暂存一个产品,任何时刻只能有一个进程课对循环缓冲池进行操作。
所有生产者和消费者要协调工作,以完成数据的交换。
只要有空缓冲区,生产者就可以把产品送入缓冲区;只要有满缓冲区,消费者就可以从缓冲区中取走物品。
为了解决生产者和消费者问题,应该设置信号量和变量如下:
full:
满缓冲区资源信号量,初值为0;
empty:
空缓冲区资源信号量 ,初值为n;
in:
生产者指针,初值均为0;
out:
消费者指针,均为0;
mutex:
缓冲区操作的互斥信号量,初值为1
三、系统结构
PCB* readyhead=NULL, * readytail=NULL; // 就绪队列——链表结构ﻫPCB*consumerhead=NULL,*consumertail=NULL; //消费者队列
PCB* producerhead=NULL,* producertail=NULL;//生产者队列ﻫprocessproc()--- 给PCB分配内存,产生相应的的进程
Pempty()---如果缓冲区满,该进程进入生产者等待队列;
linkqueue(exe,&producertail);//把就绪队列里的进程放入生产者队列的尾部
执行顺序:
Main()---empty---in---full---out---finish
当缓冲池为空时,生产者生产产品in缓冲池in=in+1
当缓冲池为满时,消费者消费产品out缓冲池out=out+1
四、PV操作代码
semaphoreempty=n;
semaphorefull=0;
semaphore mutex=1;
messagebuffer[n];
intin=0;
intout=0;
void main()
{
parbegin(proceducer(),consumer());
}
void proceducer()
{do
{prodeceanew meddage;
P(empty);
P(mutex);
sendanew messagetobuffer[in];
in=(in+1)%n;
V(mutex);
V(full);
}while(true);
}
void consumer()
{do
{P(full);
P(mutex);
getamessagefrom buffer[out];
out=(out+1)%n;
V(mutex);
V(empty);
comsumeamessage;
}while(true);
}
五、C++程序代码
#include"windows.h"
#include"iostream.h"
#include"math.h"
#definerandom(rand()*10000)/RAND_MAX //定义一个随机函数来生产产品,并且使两个顾产品间的时间少于10秒
intlongwaiting(0); //正在等待的产品的数目
intbuffer;//空位的总数目
charempty; //缓冲区空
charfull;//缓冲区满
int count(0); //产品的号码数
int finish(0);//生产完毕的产品数目
DWORDa;
void proceduce()
{
Sleep(10000);
cout<<"缓冲区已空 !
"<<endl; //生产者生产产品函数,用时10秒
}
voidgetconsum()
{
Sleep(10001); //产品被生产的函数,为了合理区分生产产品
cout<<"第"<<finish<<"个产品被消费,取出 "<<endl;
}
HANDLEMutex=CreateMutex(NULL,FALSE, "Mutex"); //用来实现进程的互斥
HANDLEproceducer=CreateSemaphore(NULL,1,1,"proceducer");//定义信号量来进行线程间的同步
HANDLEconsumer=CreateSemaphore(NULL,0,3,"consum");
DWORDWINAPI consum(LPVOIDpParm2) //消费的线程
{
WaitForSingleObject(Mutex ,INFINITE);//p(mutex)来进行互斥操作
count++;//生产的是第几个产品
cout<<"第"<if(waiting {
if(waiting!
=0)
{
cout<<"此时有"< }
else
cout<<"没有产品在等待"<<endl;//输出有多少人在等待
waiting++;
cout<<"还有"< cout<<"有空区,产品已经进入"<<endl;
ReleaseSemaphore(consum,1,NULL);//v(consumer)
ResumeThread(consum);//唤醒生产者进程
ReleaseMutex(Mutex);//释放互斥量,以便其他线程使用
WaitForSingleObject(proceducer,INFINITE);//等待生产
getconsum();//消费并取走
}
else
{
cout<<"缓冲区已满,第"<<count<<"个产品暂停生产"<<endl;//没有空位,生产者不再生产
ReleaseMutex(Mutex);
}
return0;
}
DWORD WINAPI proceducers(LPVOID pParm1)//生产者的线程
{
while(true)//一直执行
{
WaitForSingleObject(consum,INFINITE);//p(customers),等待产品
WaitForSingleObject(Mutex,INFINITE);//等待互斥量
waiting--;//等待的产品数减一
ReleaseSemaphore(proceducer,1,NULL);//释放信号量
ResumeThread(proceducer);//唤醒消费进程
ReleaseMutex(Mutex);//v(mutex);
proceduce();//生产
finish++;//消费的产品数加1
}
return0;
}
intmain(intargc,char*argv[])
{
cout<<"请输入缓冲区空位的总数目:
";
cin>>buffer;
cout<<"缓冲区共有"< cout<<"缓冲区空生产产品吗?
Y/N"<<endl;//缓冲区是否空
cin>>empty;
while(empty!
='y')
{
cout<<endl<<"********对不起,缓冲区满!
********"<<endl;
cout<<"缓冲区已空,生产产品?
Y/N"< cin>>empty;
}
HANDLEhThread1;
HANDLEhThread2;
hThread2=:
:
CreateThread (NULL,0,proceducers,NULL,0,NULL);//产生一个生产者进程
while(full!
='y')
{
Sleep(random); //产品随机进入
hThread1=:
:
CreateThread(NULL,0,consum,NULL,a,NULL);
cout<<endl<<"********缓冲区已空,请继续生产********"<<endl;
if(finish>=10&&waiting==0)//如果完成数超过10并且没有人等待
{
cout<<"已经为"<"< cin>>full;
returnfull;
}
else;
}
if(full=='y')
{
cout<<"********对不起,缓冲区已满********"< return0;
}
}
六、运行结果截图
缓冲区空位总数目为1时运行结果截图:
缓冲区空位总数目为0和3时运行结果截图(其余部分如上当缓冲区空位总数目为1时的截图)
七、参考文献
1、计算机网络操作系统原理与应用 孔宪军吕滨(本学期教科书)
2、网络操作系统课程设计计划书 陈卫老师
3、C程序设计(第三版) 谭浩强
八、实验总结
刚刚看到课程设计的内容与要求时,不禁有点无从下手的感觉。
经过一番思考后,才决定选择设计“进程机制与并发程序设计——linux下生产者与消费者的问题实现”这部分。
设计这部分不仅仅需要用到C/C++编程,还需要编写相关的PV原语。
由于自己的PV原语部分和C/C++编程学的不是很好,因此对我来说有点难。
于是我就积极利用书本上的知识来编写PV原语,C/C++编程是参考书上的指点以及网络资源编写出来的。
不懂得地方查资料、上网找、问问其他同学,最后终于慢慢的把课程设计做出来了。
通过这次课程设计,才感觉到自己还是平时动手少,要经常动手去做实验才能真正学到东西。
尤其是一些C/C++编程和PV原语的编写更需要平时多加练习才能学好用好。
特别是C/C++编程在遇到语法有多处错误时,不能急,要冷静下来慢慢修改,知道程序正确。
虽然是自己独立做的课程设计,但是其中还是有很多不懂的东西是问同学的,因此了解到学习不是单独的,应该是相互交流相互学习的。