消费者生产者问题计算机操作系统课程设计.docx

上传人:b****6 文档编号:8883102 上传时间:2023-05-15 格式:DOCX 页数:19 大小:76.54KB
下载 相关 举报
消费者生产者问题计算机操作系统课程设计.docx_第1页
第1页 / 共19页
消费者生产者问题计算机操作系统课程设计.docx_第2页
第2页 / 共19页
消费者生产者问题计算机操作系统课程设计.docx_第3页
第3页 / 共19页
消费者生产者问题计算机操作系统课程设计.docx_第4页
第4页 / 共19页
消费者生产者问题计算机操作系统课程设计.docx_第5页
第5页 / 共19页
消费者生产者问题计算机操作系统课程设计.docx_第6页
第6页 / 共19页
消费者生产者问题计算机操作系统课程设计.docx_第7页
第7页 / 共19页
消费者生产者问题计算机操作系统课程设计.docx_第8页
第8页 / 共19页
消费者生产者问题计算机操作系统课程设计.docx_第9页
第9页 / 共19页
消费者生产者问题计算机操作系统课程设计.docx_第10页
第10页 / 共19页
消费者生产者问题计算机操作系统课程设计.docx_第11页
第11页 / 共19页
消费者生产者问题计算机操作系统课程设计.docx_第12页
第12页 / 共19页
消费者生产者问题计算机操作系统课程设计.docx_第13页
第13页 / 共19页
消费者生产者问题计算机操作系统课程设计.docx_第14页
第14页 / 共19页
消费者生产者问题计算机操作系统课程设计.docx_第15页
第15页 / 共19页
消费者生产者问题计算机操作系统课程设计.docx_第16页
第16页 / 共19页
消费者生产者问题计算机操作系统课程设计.docx_第17页
第17页 / 共19页
消费者生产者问题计算机操作系统课程设计.docx_第18页
第18页 / 共19页
消费者生产者问题计算机操作系统课程设计.docx_第19页
第19页 / 共19页
亲,该文档总共19页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

消费者生产者问题计算机操作系统课程设计.docx

《消费者生产者问题计算机操作系统课程设计.docx》由会员分享,可在线阅读,更多相关《消费者生产者问题计算机操作系统课程设计.docx(19页珍藏版)》请在冰点文库上搜索。

消费者生产者问题计算机操作系统课程设计.docx

消费者生产者问题计算机操作系统课程设计

齐齐哈尔大学

操作系统课程综合实践

题目:

多进程同步方法解决生产

者一消费者问题

班级:

__0

姓名:

__0

学号:

__0

指导教师:

__0

2011年12月7日

综合实践评分表

班级

0

姓名

0

指导教师

0

题目:

多进程同步方法解决生产者一消费者问题

评分标准

评分标准

分数权重

评分的依据

得分

A

C

选题

10

选题符合大纲要求,题目较新颖,工作量大

选题基本符合大纲要求,工作量适中

工作态度

10

态度端正,能主动认真完成各个环节的工作,不迟到早退,出勤好。

能够完成各环节基本工作,出勤较好。

存储结构、算法描述

20

能正确选择存储结构,定义准确,算法流程图或类C谛言描述的算法准确无误

能止确选择存储结构,算法流程图或类C语言描述的算法基本准确

独立解决问题的能力

10

具有独立分析、解决问题能力,有f的创造性,能够独立完成软件的设计与调试工作,程序结构清晰,逻辑严谨,功能完善。

有aE的分析、斛决问题能力。

能够在老师指导下完成软件的设计与调试工作,程序功能较完善。

答辨问题回答

20

能准确回答老师提出的问题

能基本准确回答老师提出的问题

程序运行情况

10

程序运行止确、界面清晰,测试数据设计合理。

程序运行止确、界面较清晰,能给出合适的测试数据。

综合实践报告

20

格式规范,层次清晰,设计思想明确,解决问题方法合理,体会深刻。

格式较规范,设计思想基本明确,解决问题方法较合理。

总分

指导教师(签字):

注:

介于A和C之间为B级,低于C为D级和E级。

按各项指标打分后,

总分在90〜100为优,80〜89为良,70〜79为中,60〜69为及格,60分以下为不及格。

多进程同步方法解决生产者-消费者问题

摘要:

本文论述了多进程同步方法解决生产者-消费者问题的过程。

该程序使学生对操作系

统的工作机制有了初步的了解,其主要目的是使学生了解和撑握在Linux系统平台下的C

语言编程,用来解决实现生活中遇到的问题。

并以Linux系统开发平台,以及虚拟机来实现。

关键字:

生产者-消费者问题,Linux系统平台,虚拟机,信号量,线程(thread)

多进程同步方法解决生产者-消费者问题

一、课程设计所需设备

计算机一台,RedHatlinux9.03系统一套。

二、课程设计预期目的

通过研究Linux的进程机制和信号量实现生产者消费者问题的并发控

制。

三、课程设计任务

用多进程同步方法解决生产者-消费者问题

设计目的:

通过研究Linux的进程机制和信号量实现生产者消费者问题

的并发控制.

说明:

有界缓冲区内设有20个存储单元,放入/取出的数据项设定为1-20

这20个整型数.

设计要求:

1)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区

的全部内容,当前指针位置和生产者/消费者线程的标识符.

2)生产者和消费者各有两个以上.

3)多个生产者或多个消费者之间须有共享对缓冲区进行操作的函数代

码.

四、课程设计基本思想

多进程是一种非常简洁的多任务操作方式。

在Linux系统下,启动一个

新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码

段、堆栈段和数据段,这是一种烦琐的多任务工作方式。

生产者-消费者方案是多进程应用程序开发中最常用的构造之一。

因此困

难也在于此。

因为在一个应用程序中可以多次重复生产者-消费者行为,其代

码也可以如此。

设计中创建了Consumer类,该类通过在一些多进程应用程

序中促进代码重用以及简化代码调试和维护来解决这个问题。

多进程应用程

序通常利用生产者-消费者编程方案,其中由生产者进程创建重复性作业,将

其传递给作业队列,然后由消费者进程处理作业。

多进程是一种使应用程序能同时处理多个操作的编程技术。

通常有两种

不同类型的多进程操作使用多个进程:

适时事件,当作业必须在特定的时间

或在特定的间隔内调度执行时;后台处理,当后台事件必须与当前执行流并

行处理或执行时;适时事件的示例包括程序提醒、超时事件以及诸如轮询和

刷新之类的重复性操作。

后台处理的示例包括等待发送的包或等待处理的已

接收的消息。

生产者-消费者方案很适合于后台处理类别的情况。

这些情况通常围绕一

个作业“生产者”方和一个作业“消费者”方。

当然,关于作业并行执行还

有其它考虑事项。

在大多数情况下,对于使用同一资源的作业,应以FCFS的

方式按顺序处理,这可以通过使用单进程的消费者轻松实现。

通过使用这种

方法,使用单个进程来访问单个资源,而不是用多个进程来访问单个资源。

要启用标准消费者,当作业到来时创建一个作业队列来存储所有作业。

生产

者进程通过将新对象添加到消费者队列来交付这个要处理的新对象。

然后消

费者进程从队列取出每个对象,并依次处理。

当队列为空时,消费者进入休

眠。

当新的对象添加到空队列时,消费者会醒来并处理该对象。

五.详细设计

5.1、调试问题分析

为解决生产者/消费者问题,应该设置两个资源信号量,其中一个表示空

缓冲区的数目,用Full表示,其初始值为有界缓冲区的大小BUFFER_NU;M

另一个表示缓冲区中产品的数目,用Empty表示,其初始值为0o另外,由

于有界缓冲区是一个临界资源,必须互斥使用,所以还需要再设置一个互斥

信号量Mutex,起初值为1。

在生产者/消费者问题中,信号量实现两种功能。

首先,它是生产产品和

消费产品的计数器,计数器的初始值是可利用的资源数目(有界缓冲区的长

度)。

其次,它是确保产品的生产者和消费者之间动作同步的同步器。

生产者要生产一个产品时,首先对资源信号量Full和互斥信号量Mutex

进行P操作,申请资源。

如果可以通过的话,就生产一个产品,并把产品送

入缓冲区。

然后对互斥信号量Mutex和资源信号量Empty进行V操作,释放

资源。

消费者要消费一个产品时,首先对资源信号量Empty和互斥信号量Mutex

进行P操作,申请资源。

如果可以通过的话,就从缓冲区取出一个产品并消

费掉。

然后对互斥信号量Mutex和资源信号量Full进行V操作,释放资源如果缓冲区中已经没有可用资源,就把申请资源的进程添加到等待队列

的队尾。

如果有一个资源被释放,在等待队列中的第一个进程被唤醒并取得这个资源的使用权。

5.2、程序流程图

 

生产者流程结构

 

图二消费者流程结构

5.3程序自定义函数

1、voidproduce(structsem_info*);

这个函数是生产者进行的生产过程,为所有的生产者所共享。

结构体指

针用来接收生产者线程创建时传来的生产者的个人信息。

2、voidconsumer(structsem_info*);

这个函数是消费者进行的生产过程,为所有的消费者所共享。

结构体指

针用来接收消费者线程创建时传来的消费者的个人信息。

3、voidsetproduce(void);

这个函数是用来设置生产者的个数和他们的名字。

4、voidsetconsumer(void);

这个函数是用来设置消费者的个数和他们的名字。

5、voidactivepthread(int);

这个函数是用来创建生产者线程,int型参数为生产者的个数。

6、voidactivecthread(int);

这个函数是用来创建生产者线程,int型参数为生产者的个数。

7、intgettime(void);

这个函数返回来一个整数,作为线程的sleep()函数的参数。

8、voidmyscanf(void);

这个函数用来获取设置生产者和消费者的个数时的整数,确保这个数字

在0至UMAX_BUFFEER问。

5.4、系统函数调用

线程

Linux系统下的多线程遵循POSIX线程接口,称为pthread。

编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a。

Linux下pthread的实现是通过系统调用clone()来实现的。

clone()是Linux所特有的系统调用,它的使用方式类似fork。

函数pthread_create用来创建一个线程,它的原型为:

externintpthread_create__P((pthread_t*__thread,__const

pthread_attr_t*__attr,

void*(*__start_routine)(void*),void*__arg));

第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三

个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数。

第二

个参数我们也设为空指针,这样将生成默认属性的线程。

当创建线程成功时,

函数返回0,若不为0则说明创建线程失败,常见的错误返回代码为EAGAIN

和EINVAL前者表示系统限制创建新的线程,例如线程数目过多了;后者表示第二个参数代表的线程属性值非法。

创建线程成功后,新创建的线程则运

行参数三和参数四确定的函数,原来的线程则继续运行下一行代码。

函数pthread_join用来等待一个线程的结束。

函数原型为:

externintpthread_join__P((pthread_t__th,void

**__thread_return));

第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它

可以用来存储被等待线程的返回值。

这个函数是一个线程阻塞的函数,调用

它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程

的资源被收回。

一个线程的结束有两种途径,一种是函数结束了,调用它的

线程也就结束了;另一种方式是通过函数pthread_exit来实现。

它的函数原

型为:

externvoidpthread_exit__P((void*__retval))__attribute__

((__noreturn__));

唯一的参数是函数的返回代码,只要pthread_join中的第二个参数thread_return不是NULL这个值将被传递给thread_return。

最后要说明的是,一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返

回,其余调用pthread_join的线程则返回错误代码ESRCH

信号量

信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。

当公共资源增加时,调用函数sem_post()增加信号量。

只有当信号量值大于0时,才能使用公共资源,使用后,函数sem_wait()减少信号量。

函数sem_trywait()和函数pthread_mutex_trylock()起同样的作用,它是

函数sem_wait()的非阻塞版本。

它们都在头文件

/usr/include/semaphore.h中定义。

信号量的数据类型为结构sem_t,它本质上是一个长整型的数。

函数sem_init

()用来初始化一个信号量。

它的原型为:

externintsem_init__P((sem_t*__sem,int__pshared,unsignedint

__value));

sem为指向信号量结构的一个指针;pshared不为0时此信号量在进程间共

享,否则只能为当前进程的所有线程共享;value给出了信号量的初始值。

函数sem_post(sem_t*sem)用来增加信号量的值。

当有线程阻塞在这个信

号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由

线程的调度策略决定的。

函数sem_wait(sem_t*sem)被用来阻塞当前线程直到信号量sem的值大于

0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。

函数

sem_trywait(sem_t*sem)是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。

函数sem_destroy(sem_t*sem)用来释放信号量sem。

六.源程序清单

6.1、源程序

#include

#include

#include

#include

typedefHANDLESemaphore;//信号量的Window嫄型

#defineP(S)WaitForSingleObject(S,INFINITE)//定义

Windows^的P操作

#defineV(S)ReleaseSemaphore(S,1,NULL)//定义Windows下的V操作

#definerate1000

#defineCONSUMER_NUM2/*消费者个数*/

#definePRODUCER_NUM3/*生产者个数*/

#defineBUFFER_NUM20/*缓冲区个数*/

char*thing[8]={"鸡腿堡","薯条","可乐","三明治","面包","

小笼包","火腿","馒头"};〃生产和消费的产品名称

structBuffer

{

intproduct[BUFFER_NUM];//缓冲区

intstart,end;//两个指针相当于教材中的in

out指针}g_buf;

SemaphoreEmpty,Full,Mutex;//分别相当于Empty,Full,

Mutex三个信号量

/**************消费者线程*****************************/DWORDWINAPIConsumer(LPVOIDpara)

{

//i表示第i个消费者

inti=*(int*)para;〃利用para传入当前消费者的编号

intptr;//待消费的内容的指针

printf("消费者%化:

需要资源\n",i);

intj=0;

while(j++<4){

//等待产品

P(Full);

//有产品,先锁住缓冲区

P(Mutex);

//记录消费的物品

ptr=g_buf.start;

//再移动缓冲区指针

g_buf.start=(g_buf.start+1)%BUFFER_NUM;

//让其他消费者或生产者使用

printf("消费者%01d:

我需要buf[%d]=%s\n",i,ptr,thing[g_buf.product[ptr]]);

〃彳肖费完毕,并释放一个缓冲

printf("消费者%01d:

我消费完毕%s\n",

i,thing[g_buf.product[ptr]]);

V(Mutex);

V(Empty);

Sleep(rate*rand()%10+110);

}

return0;

}

/****************

生产者线程

******************************

**/

DWORDWINAPIProducer(LPVOIDpara){

inti=*(int*)para-CONSUMER_NUM;

intptr;

intdata;〃产品

intj=0;

while(j++<4)

{

data=rand()%8;

printf("生产者%01d:

生产出:

%s!

\n",i,thing[data]);

//等待存放空间

P(Empty);

//有地方,先锁住缓冲区

P(Mutex);

//记录消费的物品

ptr=g_buf.end;

//再移动缓冲区指针

g_buf.end=(g_buf.end+1)%BUFFER_NUM;

printf("不产者%0化:

放到缓冲区

buf[%d]=%s\n",i,ptr,thing[data]);

g_buf.product[ptr]=data;

一//放好了完毕,释放一个产品

//让其他消费者或生产者使用

V(Mutex);

V(Full);

Sleep(rate/2*rand()%10+110);

}

return0;

}

intmain(intargc,char*argv口)

{

//线程技术,前面为消费者线程,后面为生产者线程

HANDLEhThread[CONSUMER_NUM+PRODUCER_NUM];〃线

srand(time(NULL));

rand();

DWORDtid;

inti=0;

//初始化信号量

Mutex=CreateSemaphore(NULL,1,1,"MutexOfConsumerAndProducer");

Empty=CreateSemaphore(NULL,BUFFER_NUM,BUFFER_NUM,"BufferSemaphone");

Full=CreateSemaphore(NULL,0,BUFFER_NUM'ProductSemaphone");

if(!

Empty||!

Full||!

Mutex)

{

printf("CreateSemaphoneError!

\n");

return-1;

}

inttotalThreads=CONSUMER_NUM+PRODUCER_NUM;

//开启消费者线程

printf("先请消费者上席!

\n");

for(i=0;i

{

hThread[i]=CreateThread(NULL,0,Consumer,&i,0,&tid);

if(hThread[i])WaitForSingleObject(hThread[i],10);

}

printf("生产者就位!

\n");

for(;i

{

hThread[i]=CreateThread(NULL,0,Producer,&i,0,&tid);

if(hThread[i])WaitForSingleObject(hThread[i],10);

}

//生产者和消费者的执行

WaitForMultipleObjects(totalThreads,hThread,TRUE,INFINITE);return0;

}

6.2、编译及运行结果

在程序中设置了两个消费者,三个生产者,为便于描述出生产-消费的

过程,我用食物代表被缓冲区消费的资源。

在实验结果中我们可以看到几个生产者生产的食物放在缓冲区中,消费者需求的话就去缓冲区去取。

在同一个时间点上不必生产者生产一个消费者就消费一个,消费者某个时间消费的资源有可能是上一个生产者所生产的。

由于按题目要求设置的缓冲区为20,

所以缓冲区没有溢出到等待消费者消费的情况。

图三运行结果

七.课程设计总结

本次课程设计通过模拟计算机操作系统中经典的“生产者一消费者问

题”,巩固了我在操作系统原理课上所学的知识,加深了对操作系统中进程同步和互斥等问题,完成了多进程同步方法解决生产者-消费者问题全部过程,结果满足设计要求。

设计过程中遇到不少困难,在反复研究老师的PPT及课本的原理后才逐

渐明晰怎样将代码实现,虽然这学期学过Java,但java不是很熟悉,因此

还是选择C+邮言。

以前学习C+般有深入了解到线程这个概念,在学习Java的时候才知道有专门的线程类。

所以我在网上也参考了其他人用C+编写尤

其是关于多进程程序的设计实现。

在代码的实现过程中,我是主要定义了两

个函数DWORDWINAPIConsumer(LPVOIDpara)和DWORDWINAPIProducer(LPVOIDpara),在这两个函数中实现PV操作。

通过本次设计,我较好地掌握了通过研究Linux的进程机制和信号量实

现生产者消费者问题的并发控制全过程,尤其是对多进程程序设计方法有了

更深的理解,开拓了思路,锻炼了实践动手能手。

但是我觉得课程设计的时

间有点短,中间又夹杂着好几场考试,所以没能做出界面以便于直观的观察

出详细过程,只是用代码实现了要描述的功能且达到了要求,所以改进的空间还比较大。

参考文献

[1]汤子瀛.《计算机操作系统》(修订版).西安电子科技大学出版社,2001。

[2]计算机操作系统教程.孙钟秀等编著.高等教育出版社,2010年8月出版

[3]数据结构教程.李春葆等编著清华大学出版社.2009年4月

[4]面向对象程序设计与VisualC++6.0教程陈天华编著清华大学出版

社.2009年7月

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 初中教育 > 语文

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2