操作系统课设报告.docx
《操作系统课设报告.docx》由会员分享,可在线阅读,更多相关《操作系统课设报告.docx(14页珍藏版)》请在冰豆网上搜索。
![操作系统课设报告.docx](https://file1.bdocx.com/fileroot1/2023-1/10/db0026ea-74bf-43e8-8b14-1638dbdb14a4/db0026ea-74bf-43e8-8b14-1638dbdb14a41.gif)
操作系统课设报告
操作系统课程设计报告
题目:
生产者-消费者问题
专业:
网络工程
班级:
网络111
学号:
201110314003
姓名:
吴超
上海海事大学信息工程学院
2013年12月15日
目录
1.课程设计任务描述与要求1
2.系统总体结构描述和主要数据结构说明1
3.课程设计报告内容3
4.总结20
附录:
程序使用说明21
1.课程设计任务描述与要求
1.1任务描述
程序首先读入data文件,根据文件内容建立相应数量的线程,类型为P的线程为生产者,类型为C的线程为消费者;建立一个链表,作为缓冲区,用来存放生产者生产的产品,每个产品占用一个链表结点,消费者从该链表中读取产品信息。
1.2任务要求
每个线程根据文件中定义的等待时间,调用Sleep()函数休眠,然后根据“生产或消费产品的数量”字段生产或消费产品;若链表中无产品可以消费,那么消费者需要等待。
每次放入或消费产品成功后,向result结果文件中写入一行记录,记录格式如下:
线程编号、类型、本次生产或消费产品的数量。
生产者和消费者信息存放在data文件中,格式如下:
1
P
3
3
2
C
5
2
3
P
8
1
4
P
7
2
5
C
8
2
6
C
9
3
各数据的含义如下:
线程编号
类型
等待时间(秒)
生产或消费产品的数量
1
P(生产者)
3
3
2
C(消费者)
5
2
3
P(生产者)
8
1
4
P(生产者)
7
3
5
C(消费者)
8
2
6
C(消费者)
12
3
2.系统总体结构描述和主要数据结构说明
2.1系统总体结构描述
设计了两个主要函数:
生产者函数、消费者函数;
设计了三个信号量:
full信号量,判断缓冲区是否有值,初值为0;
empty信号量,判断缓冲区是否有空缓冲区,初值为缓冲区数;
mutex信号量作为互斥信号量,用于互斥的访问缓冲区。
生产者函数通过执行P操作信号量empty减1,判断缓冲区是否有空。
有空则互斥的访问缓冲区并放入数据,然后释放缓冲区,执行操作,信号量full加1。
消费者函数执行P操作,信号量full减1,判断是否有数据,有则互斥的访问缓冲区并取走数据,然后释放缓冲区,执行操作,empty信号量加1。
3.课程设计报告内容
3.1模块功能
该实验主要分为三大模块:
1.主程序,创建并控制程序的流程,
其中控制线程的活动以及信号量的操作,如图3-1-1所示;
2.生产者模块:
生产者对缓冲区的操作,如图3-1-2所示;
3.消费者模块:
消费者对缓冲区的操作,如图3-1-3所示。
3.2详细流程图
图3-1-1主程序
图3-1-2生产者图3-1-3消费者
通过分析,我们已经了解到了可以采用信号量来解决n个进程的临界区问题,这n个进程共享一个信号量mutex(mutualexclusion),并初始化为1。
每个进程Pi的组织结构如下图。
由于本系统我们研究的是有限缓冲区(Bounded-Buffer)的生产者消费者问题。
而且根据初始条件可知,该缓冲区内有20个缓冲项,每个缓冲项存储一个整形数。
信号量mutex提供了对缓冲池访问的互斥要求,并初始化为1。
信号量empty和full分别用来表示空缓冲项和满缓冲项的数量。
信号量empty初始化为20,而信号量full初始化为0;
生产者进程和消费者进程的代码如图。
注意生产者和消费者之间的对称性可以这样来理解代码:
生产者为消费者生产满缓冲项,或消费者为生产者生产空缓冲项。
3.3程序清单和详细注释
#include
#include
#include
#include
#include
#include
#include
#include
#include
usingnamespacestd;
constintArraySize=100;
constintBuffer_Number=10;
HANDLEempty,full,mutex;
char*produce[10]={"Product_1","Product_2","Product_3","Product_4","Product_5","Product_6","Product_7","Product_8","Product_9","Product_10"};
structBuffer
{
intarray[Buffer_Number];
intin,out;
}buffer;
structProcParam{
intthreadID;
chartype;
doublewait_time;
intcount;
};
//生产者线程
unsigned__stdcallProducer(void*arg)
{
ProcParam*param;//定义一个param数组,数组的每个单元存放一个对应线程的参数
param=(ProcParam*)arg;
intnextp;
intproduce_num;
intcount=param->count;
intt=param->wait_time;
printf("线程号码%d是%c,生产中...正在生产%d个\n",param->threadID,param->type,count);
while(count--)
{
Sleep(t);
produce_num=rand()%10;
printf("线程%d:
产出产品:
%s\n",param->threadID,produce[produce_num]);
WaitForSingleObject(empty,-1);
WaitForSingleObject(mutex,-1);
nextp=buffer.in;
buffer.in=(buffer.in+1)%Buffer_Number;
printf("线程%d:
正在向array[%d]丢产品:
%s\n",param->threadID,nextp,produce[produce_num]);
ofstreamoutFile;//同时将该信息写入磁盘的某txt文件中,该函数要#include
outFile.open("result.txt",ios:
:
app);//该txt文件名可自己命名,第1次open时磁盘中没有该文件,系统会创建一个空白的。
outFile<<"ThreadID="<threadID<<"类别:
"<type<<""<<"生产数量:
"<<1<<"";
outFile<outFile.close();
buffer.array[nextp]=produce_num;
ReleaseSemaphore(mutex,1,NULL);
ReleaseSemaphore(full,1,NULL);
}
return0;
}
//消费者线程
unsigned__stdcallConsumer(void*arg)
{
ProcParam*param;
param=(ProcParam*)arg;
intnextc;
intcon_num;
intcount=param->count;
intt=param->wait_time;
while(count--)
{
printf("线程号码%d是%c:
消费中...\n",param->threadID,param->type);
WaitForSingleObject(full,-1);
WaitForSingleObject(mutex,-1);
nextc=buffer.out;
buffer.out=(buffer.out+1)%Buffer_Number;
con_num=buffer.array[nextc];
printf("线程%d:
正在消费位于编号array[%d]的产品:
%s\n",param->threadID,nextc,produce[con_num]);
ofstreamoutFile;//同时将该信息写入磁盘的某txt文件中,该函数要#include
outFile.open("result.txt",ios:
:
app);//该txt文件名可自己命名,第1次open时磁盘中没有该文件,系统会创建一个空白的。
outFile<<"ThreadID="<threadID<<"类型:
"<type<<"消费数量:
"<<1<<"";
outFile<outFile.close();
ReleaseSemaphore(mutex,1,NULL);
ReleaseSemaphore(empty,1,NULL);
Sleep(t);
}
return0;
}
int_tmain(intargc,_TCHAR*argv[])
{
ProcParam*param=newProcParam[ArraySize];
HANDLEhThread[ArraySize];
intThreadNum[ArraySize];
unsignedintthreadID[ArraySize];
inti=0,threadnumber,totalThreads=0;
//初始化信号量
mutex=CreateSemaphore(NULL,1,1,NULL);
empty=CreateSemaphore(NULL,Buffer_Number,Buffer_Number,NULL);
full=CreateSemaphore(NULL,0,Buffer_Number,NULL);
if(!
empty||!
full||!
mutex)
{
printf("CreateSemaphoneError!
\n");
return-1;
}
//初始化缓冲区的in和out指针变量
buffer.in=0;
buffer.out=0;
//读取文件data.txt
ifstreaminFile;
inFile.open("data.txt");
while(inFile)
{
inFile>>param[i].threadID;
inFile>>param[i].type;
inFile>>param[i].wait_time;
inFile>>param[i].count;
i++;
inFile.get();
}
threadnumber=0;
totalThreads=0;
intw=i;
for(i=0;iif(param[i].type=='P')
{
totalThreads++;
ThreadNum[threadnumber]=i+1;
hThread[threadnumber]=(HANDLE)_beginthreadex(NULL,0,Producer,(void*)¶m[threadnumber],0,&threadID[i]);
threadnumber++;
}
else
{
totalThreads++;
ThreadNum[threadnumber]=i+1;
hThread[threadnumber]=(HANDLE)_beginthreadex(NULL,0,Consumer,(void*)¶m[threadnumber],0,&threadID[i]);
threadnumber++;
}
}
//等待所有的生产者和消费者执行完毕
WaitForMultipleObjects(totalThreads,hThread,true,INFINITE);
//关闭所有打开的句柄
for(i=0;iCloseHandle(mutex);
CloseHandle(empty);
CloseHandle(full);
printf("程序即将结束。
\n");
getchar();
return0;
}
3.4程序执行结果截图
3.4.1生产者消费者截图
图3-4-1创建线程截图
3.4.2自动生成记录截图
图3-4-2自动生成记录截图
4.总结
本次的实验是在刚刚接触到操作系统这门课之后,伴随着操作系统这门课的学习,对于这门课的认识也更加深刻,包括此次做的实验内容,生产者消费者问题也有了一定的认识。
生产者进程和消费真进程共享一个有若干数据位置的缓冲区,缓冲区中有n个存放数据的位置,生产者生产产品放入缓冲区,而消费从缓冲中取产品消费,只要缓冲未满,生产者就可以将生产的产品放入缓冲,这种同步规则同时也就表明,如果缓冲区产品满,没有空的位置,则生产者就只能等待消费者取走产品,如果缓冲中没有产品,消费者就不能取产品消费,只能等待生产者放入产品。
为解决生产者和消费者进程同步的问题,设置两个信号灯full和empty。
这里,信号灯有两个功能:
首先它是资源生产和消费的计数器,其次,它是生产者和消费者之间的同步器。
信号灯full表示缓冲中存放的产品的数量,初始值为0,每当生产者生产一个产品放入缓冲后。
就执行v(full)操作,就是加1操作,表示缓冲区中加入一个产品,每当消费者在取走产品前,执行p(full)操作,其作用是判断缓冲中是否有产品,如果有,则取走一个产品。
P操作使得产品数量减一。
另外,由于有界缓冲区是一个临界资源,必须互斥使用,因此,需要设置一个互斥灯信号mutex,其初始值为1.
本来对于这个问题不是很明白,但是经过问老师和同学的交流,终于找到了方法,用了上面的方法来解决这个问题。
感觉到自己对于这方面的知识还有所欠缺,必须认真努力的好好学习。
这次的课程设计是大学生活中相当有意义的一次。
参考书目:
[1]刘腾红、骆正华,计算机操作系统(北京,清华大学出版社,2008年;
[2]张坤。
姜立秋、赵慧然,操作系统实验教程(北京,清华大学出版社,2008年;
[3]汤小丹、梁红兵、哲凤屏、汤子瀛,计算机操作系统,西安电子科技大学出版社,2007年。