操作系统课程设计“生产者-消费者”问题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
《操作系统》课程设计
题目:“生产者-消费者”问题
学院:信息工程学院
专业:计算机科学与技术
班级:计科1302
*名:***
指导老师:***
2016年1月 15日
目录
一、课程设计目标 (2)
二、课题内容 (2)
1.实验目的 (2)
2、实验环境 (2)
3、实验要求 (2)
三、设计思路 (3)
1.信号量的设置 (3)
2.系统结构 (4)
3.程序流程图 (5)
4.P V操作代码 (6)
四、源代码 (7)
五、运行与测试 (10)
六、心得体会 (12)
一、课程设计目标
学习System V的进程间通信机制,使用信号量和共享内存实现经典进程同步问题“生产者-消费者”问题。
具体要求:
1.创建信号量集,实现同步互斥信号量。
2.创建共享内存,模拟存放产品的公共缓冲池。
3.创建并发进程,实现进程对共享缓冲池的并发操作。
二、课题内容
1.实验目的
(1)掌握基本的同步互斥算法,理解生产者和消费者同步的问题模型。
(2)了解linux中多线程的并发执行机制,线程间的同步和互斥。
2、实验环境:C/C++语言编译器
3、实验要求
(1)创建生产者和消费者线程
在linux环境下,创建一个控制台进程,在此进程中创建n个线程来模拟生产者或者消费者。
这些线程的信息由本程序定义的“测试用例文件”中予以指定。
(2)生产和消费的规则
在按照上述要求创建线程进行相应的读写操作时,还需要符合以下要求:
①共享缓冲区存在空闲空间时,生产者即可使用共享缓冲区。
②从上边的测试数据文件例子可以看出,某一生产者生产一个产品后,可能不止一个消费者,或者一个消费者多次地请求消费该产品。
此时,只有当所有的消费需求都被满足以后,该产品所在的共享缓冲区才可以被释放,并作为空闲空间允许新的生产者使用。
③每个消费者线程的各个消费需求之间存在先后顺序。
例上述测试用例文件包含一行信息“5 C 3 l 2 4”,可知这代表一个消费者线程,该线程请求消费1,2,4号生产者线程生产的产品。
而这种消费是有严格顺序的,消费1号线程产品的请求得到满足后才能继续往下请求2号生产者线程的产品。
④要求在每个线程发出读写操作申请、开始读写操作和结束读写操作时分别显示提示信息。
(3)相关基础知识
本实验所使用的生产者和消费者模型具有如下特点:
本实验的多个缓冲区不是环形循环的,也不要求按顺序访问。
生产者可以把产品放到目前某一个空缓冲区中。
消费者只消费指定生产者的产品。
在测试用例文件中指定了所有的生产和消费的需求,只有当共享缓冲区的数据满足了所有关于它的消费需求后,此共享缓冲区才可以作为空闲空间允许新的生产者使用。
本实验在为生产者分配缓冲区时各生产者间必须互斥,此后各个生产者的具体生产活动可以并发。
而消费者之间只有在对同一产品进行消费时才需要互斥,同时它们在消费过程结束时需要判断该消费对象是否已经消费完毕并清除该产品。
linux用来实现同步和互斥的实体。
在linux中,常见的同步对象有:信号量(Semaphore)、互斥量(Mutex)、临界段(CriticalSection)等。
使用这些对象都分为三个步骤,一是创建或者初始化:接着请求该同步对象,随即进入临界区,这一步对应于互斥量的上锁;最后释放该同步对象,这对应于互斥量的解锁。
这些同步对象在一个线程中创建,在其他线程中都可以使用,从而实现同步互斥。
三、设计思路
1.信号量的设置
生产者进程与消费者进程是经典的同步互斥关系。
系统创建两类进程:proceducer ()和consumer(),分别用来描述生产者和消费者的行为。
生产者与消费者问题是指若干进程通过循环缓冲池区交换数据。
如下图所示,生产者进程不断向循环缓冲池区中写入数据(即生产数据),而消费者进程不断从循环缓冲池区中读出数据(即消费数据)。
循环缓冲池共有N个缓冲区,缓冲区可以暂存一个产品,任何时刻只能有一个进程课对循环缓冲池进行操作。
所有生产者和消费者要协调工作,以完成数据的交换。
只要有空缓冲区,生产者就可以把产品送入缓冲区;只要有满缓冲区,消费者就可以从缓冲区中取走物品。
为了解决生产者和消费者问题,应该设置信号量和变量如下:
full:满缓冲区资源信号量,初值为0;
empty:空缓冲区资源信号量,初值为n;
in:生产者指针,初值均为0;
out:消费者指针,均为0;
mutex:缓冲区操作的互斥信号量,初值为1
2.系统结构
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
3. 程序流程图
图一生产者流程结构
图二消费者流程结构
4.PV操作代码
semaphore empty=n;
semaphore full=0;
semaphore mutex=1;
message buffer[n];
int in=0;
int out=0;
void main()
parbegin(proceducer(),consumer());
}
void proceducer()
{ do
{ prodece a new meddage;
P(empty);
P(mutex);
send a new message to buffer[in];
in=(in+1)%n;
V(mutex);
V(full);
} while(true);
}
void consumer()
{ do
{ P(full);
P(mutex);
get a message from buffer[out];
out=(out+1)%n;
V(mutex);
V(empty);
comsume a message;
}while(true);
}
四、源代码
#include "windows.h"
#include "iostream.h"
#include "math.h"
#define random (rand()*10000)/RAND_MAX //定义一个随机函数来生产产品,并且使两个顾产品间的时间少于10秒
int long waiting(0); //正在等待的产品的数目
int buffer; //空位的总数目
char empty; //缓冲区空
char full; //缓冲区满
int count(0); //产品的号码数
int finish(0); //生产完毕的产品数目
DWORD a;
void proceduce()
Sleep (10000);
cout<<"缓冲区已空!"<<endl; //生产者生产产品函数,用时10秒
}
void getconsum()
{
Sleep (10001); //产品被生产的函数,为了合理区分生产产品
cout<<"第"<<finish<<"个产品被消费,取出"<<endl;
}
HANDLE Mutex=CreateMutex(NULL, FALSE, "Mutex"); //用来实现进程的互斥HANDLE proceducer=CreateSemaphore(NULL, 1,1, "proceducer");//定义信号量来进行线程间的同步
HANDLE consumer=CreateSemaphore(NULL,0,3,"consum");
DWORD WINAPI consum(LPVOID pParm2) //消费的线程
{
WaitForSingleObject(Mutex ,INFINITE); //p(mutex)来进行互斥操作
count++; //生产的是第几个产品
cout<<"第"<<count<<" 个产品生产了"<<endl;
if (waiting<buffer) //如果缓冲池还有空位
{
if (waiting!=0)
{
cout<<"此时有"<<waiting+1 <<" 个产品等待消费"<<endl;
}
else
cout<<"没有产品在等待"<<endl; //输出有多少人在等待
waiting++;
cout<<"还有"<<buffer-waiting<<"个空位"<<endl;
cout<<"有空区,产品已经进入"<<endl;
ReleaseSemaphore(consum,1,NULL);//v(consumer)
ResumeThread(consum);//唤醒生产者进程
ReleaseMutex(Mutex);//释放互斥量,以便其他线程使用
WaitForSingleObject(proceducer,INFINITE);//等待生产
getconsum(); //消费并取走
}
else
{
cout<<"缓冲区已满,第"<<count<<"个产品暂停生产"<<endl; //没有空位,生产者不再生产
ReleaseMutex(Mutex);
}
return 0;
}
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
}
return 0;
}
int main(int argc, char* argv[])
{
cout<<"请输入缓冲区空位的总数目:";
cin>>buffer;
cout<<"缓冲区共有"<<buffer<<"个空位"<<endl; //设置缓冲区空位数目
cout<<"缓冲区空生产产品吗?Y/N"<<endl; //缓冲区是否空
cin>>empty;
while (empty!='y')
{
cout<<endl<<"********对不起,缓冲区满!********"<<endl;
cout<<"缓冲区已空,生产产品?Y/N"<<endl;
cin>>empty;
}
HANDLE hThread1;
HANDLE hThread2;
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<<"已经为"<<finish<<"个产品了,要停止生产吗?"<<endl; //提示是否关门
cin>>full;
return full;
}
else ;
}
if (full=='y')
{
cout<<"********对不起,缓冲区已满********"<<endl;
return 0;
}
}
五、运行与测试
缓冲区空位总数目为1时运行结果截图:
缓冲区空位总数目为0和3时运行结果截图(其余部分如上当缓冲区空位总数目为1时的截图)
六、心得体会
本次课程设计通过模拟计算机操作系统中经典的“生产者—消费者问题”,巩固了我在操作系统原理课上所学的知识,加深了对操作系统中进程同步和互斥等问题,完成了多进程同步方法解决生产者-消费者问题全部过程,结果满足设计要求。
在这次的课程设计中,我遇到了很大的困难,对Linux操作系统不熟悉,所以我在Windows操作系统上实现这个程序。
这个课程设计并不是很完美,但是起码能让我们很好的理解了什么是生产者—消费者问题。
让我对互斥问题有了更深的见解,同时也认识的到自己很大的不足,在以后的学习中会加以克服,增强自己的问题分析能力和动手实践能力。