生产者消费者 BoundedBuffer Problem.docx
《生产者消费者 BoundedBuffer Problem.docx》由会员分享,可在线阅读,更多相关《生产者消费者 BoundedBuffer Problem.docx(16页珍藏版)》请在冰豆网上搜索。
生产者消费者BoundedBufferProblem
课程设计任务书
学生姓名:
专业班级:
软件0703
指导教师:
刘军工作单位:
计算机科学与技术学院
题目:
实现生产者消费者(Bounded-BufferProblem)问题
初始条件:
1.操作系统:
Linux
2.程序设计语言:
C语言
3.有界缓冲区内设有20个存储单元,其初值为0。
放入/取出的数据项按增序设定为1-20这20个整型数。
要求完成的主要任务:
(包括课程设计工作量及其技术要求,以及说明书撰写等具体要求)
1.技术要求:
1)为每个生产者/消费者产生一个线程,设计正确的同步算法
2)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的当前全部内容、当前指针位置和生产者/消费者线程的自定义标识符。
3)生产者和消费者各有两个以上。
4)多个生产者或多个消费者之间须共享对缓冲区进行操作的函数代码。
2.设计说明书内容要求:
1)设计题目与要求
2)总的设计思想及系统平台、语言、工具等。
3)数据结构与模块说明(功能与流程图)
4)运行结果与运行情况
(提示:
(1)有界缓冲区可用数组实现。
(2)编译命令可用:
cc-lpthread-o 目标文件名 源文件名
(3)多线程编程方法参见附件。
)
3.调试报告:
1)调试记录
2)自我评析和总结
上机时间安排:
周一~五下午14:
00-18:
00(6月15日开始)
指导教师签名:
2010年6月15日
系主任(或责任教师)签名:
2010年6月15日
实现生产者消费者(Bounded–BufferProblem)问题
摘要
生产者与消费者问题是《操作系统》中经典进程同步问题的典型代表。
本设计介绍了基于单缓冲区和多缓冲区的生产者与消费者问题在C语言中的多种实现机制。
这种用C实现生产者与消费者问题的思想不仅可以更好的理解这方面的内容,而且还具有很强的实践意义。
1设计题目与要求
1.1设计题目:
实现生产者消费者(Bounded–BufferProblem)问题
1.2设计要求:
通过研究Linux的线程机制和信号量实现生产者消费者(BoundedBuffer)问题的并发控制。
2总的设计思想及系统平台、语言、工具
2.1设计思想:
2.1.1具体的要求
(1)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容.当前指针位置和生产者/消费者线程的标识符
(2)生产者和消费者各有两个以上
(3)多个生产者或多个消费者之间须共享对缓冲区进行操作的函数代码。
2.1.2POSIX无名信号量
PV操作是原子操作.也就是操作是不可以中断的,在一定的时间内,只能够有一个进程的代码在CPU上面执行.在系统当中,有时候为了顺利的使用和保护共享资源,提出了信号的概念.POSIX标准提出了有名信号量和无名信号量的概念,由于Linux只实现了无名信号量,我们在这里就只是介绍无名信号量了。
信号量的使用主要是用来保护共享资源,使的资源在一个时刻只有一个进程所拥有.为此可以使用一个信号灯.当信号灯的值为某个值的时候,就表明此时资源不可以使用.否则就表>示可以使用.为了提供效率,Linux系统提供了下面几个函数
POSIX的无名信号量的函数有以下几个:
intsem_init(sem_t*sem,intpshared,unsignedintvalue);
intsem_destroy(sem_t*sem);
intsem_wait(sem_t*sem);
intsem_trywait(sem_t*sem);
intsem_post(sem_t*sem);
intsem_getvalue(sem_t*sem);
sem_init创建一个信号灯,并初始化其值为value.pshared决定了信号量能否在几个进程间共享.由于目前Linux还没有实现进程间共享信号灯,所以这个值只能够取0.sem_destroy是用来删除信号灯的.sem_wait调用将阻塞进程,直到信号灯的值大于0.这个函数返回的时候自动的将信号灯的值的件一.sem_post和sem_wait相反,是将信号灯的内容加一同时发出信号唤醒等待的进程..sem_trywait和sem_wait相同,不过不阻塞的,当信号灯的值为0的时候返回EAGAIN,表示以后重试.sem_getvalue得到信号灯的值.
这几个函数的使用相当简单的.比如我们有一个程序要向一个系统请求一个资源时.首先创建一个信号灯,并使其初始值为1,表示有一个资源可用.然后一个进程调用sem_wait由于这个时候信号灯的值为1,所以这个函数返回,打印机开始打印了,同时信号灯的值为0了.如果第二个进程要使用,调用sem_wait时候,由于信号灯的值为0,资源不可用,于是被阻塞了.当第一个进程对资源的使用完毕以后,调用sem_post信号灯的值为1了,这个时候系统通知第二个进程,于是第二个进程的sem_wait返回.第二个进程开始工作了.
2.1.3SystemV信号量
为了解决上面的问题,也可以使用SystemV信号量.并且Linux实现了SystemV信号量.这样就可以用实例来解释了.SystemV信号量的函数主要有下面几个.
key_tftok(char*pathname,charproj);
intsemget(key_tkey,intnsems,intsemflg);
intsemctl(intsemid,intsemnum,intcmd,unionsemunarg);
intsemop(intsemid,structsembuf*spos,intnspos);
structsembuf{
shortsem_num;/*使用那一个信号*/
shortsem_op;/*进行什么操作*/
shortsem_flg;/*操作的标志*/
};
ftok函数是根据pathname和proj来创建一个关键字.semget创建一个信号量.成功时返回信号的ID,key是一个关键字,可以是用ftok创建的也可以是IPC_PRIVATE表明由系统选用一个关键字.nsems表明我们创建的信号个数.semflg是创建的权限标志,和创建一个文件的标志相同.
semctl对信号量进行一系列的控制.semid是要操作的信号标志,semnum是信号的个数,cmd是操作的命令.经常用的两个值是:
SETVAL(设置信号量的值)和IPC_RMID(删除信号灯).arg是一个给cmd的参数.
semop是对信号进行操作的函数.semid是信号标志,spos是一个操作数组表明要进行什么操作,nspos表明数组的个数.如果sem_op大于0,那么操作将sem_op加入到信号量的值中,并唤醒等待信号增加的进程.如果为0,当信号量的值是0的时候,函数返回,否则阻塞直到信号量的值为0.如果小于0,函数判断信号量的值加上这个负值.如果结果为0唤醒等待信号量为0的进程,如果小与0函数阻塞.如果大于0,那么从信号量里面减去这个值并返回.
2.1.4pthread_xxx()API
主要包含数据结构pthread_t它记录一个线程的号,主要包括下面几个函数,完成不同的功能:
intpthread_create(pthread_t*thread,pthread_attr_t*attr,void*(*start_routine)(void*),void*arg);创建一个线程。
pthread_join(pthread_t*thread,void**return);等待一个线程结束。
pthread_exit(void*returnval);结束一个线程。
2.2.系统平台:
一台Linux主机且有超级用户权限
2.3.编程工具:
VI编辑器,Gedit编辑器
3.模块说明
3.1.生产者进程:
if(fork()==0)
{
inti=0;
while(i<100)
{
semop(emptyid,&P,1);
semop(mutxid,&P,1);
array[*(set)%MAXSEM]=i+1;
printf("Producer%d\n",array[(*set)%MAXSEM]);
(*set)++;
semop(mutxid,&V,1);
semop(fullid,&V,1);
i++;
}//endofwhileinline62
sleep(10);
printf("Producerisover");
exit(0);
}/……
3.2消费者进程:
//消费者A进程
if(fork()==0)
{
while
(1)
{
semop(fullid,&P,1);
semop(mutxid,&P,1);
if(*get==100)
break;
*sum+=array[(*get)%MAXSEM];
printf("TheComsumerAGetNumber%d\n",array[(*get)%MAXSEM]);
(*get)++;
if(*get==100)
printf("Thesumis%d\n",*sum);
semop(mutxid,&V,1);
semop(emptyid,&V,1);
sleep
(1);
}//endofwhile
(1)inline82
printf("ConsumerAisover");
exit(0);
}//endofifinline81
else
{//消费者B进程
if(fork()==0)
{
while
(1)
{
semop(fullid,&P,1);
semop(mutxid,&P,1);
if(*get==100)
break;
*sum+=array[(*get)%MAXSEM];
printf("TheComsumerBGetNumber%d\n",array[(*get)%MAXSEM]);
(*get)++;
if(*get==100)
printf("Thesumis%d\n",*sum);
semop(mutxid,&V,1);
semop(emptyid,&V,1);
sleep
(1);
}//endofwhile
(1)inline105
printf("ConsumerBisover");
exit(0);
}//endofifinline103
}//endofelseinline101
}……
4.源程序:
#include
#include
#include
#include
#include
#include
#include
#include
#defineMAXSEM5
////声明三个信号灯ID
intfullid;
intemptyid;
intmutxid;
intmain()
{
structsembufP,V;;
unionsemunarg;
////声明共享内存
int*array;
int*sum;
int*set;
int*get;
//映射共享内存
array=(int*)mmap(NULL,sizeof(int)*5,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
sum=(int*)mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
get=(int*)mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
set=(int*)mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
*sum=0;
*get=0;
*set=0;
//生成信号灯
fullid=semget(IPC_PRIVATE,1,IPC_CREAT|00666);
emptyid=semget(IPC_PRIVATE,1,IPC_CREAT|00666);
mutxid=semget(IPC_PRIVATE,1,IPC_CREAT|00666);
//为信号灯赋值
arg.val=0;
if(semctl(fullid,0,SETVAL,arg)==-1)perror("semctlsetvalerror");
arg.val=MAXSEM;
if(semctl(emptyid,0,SETVAL,arg)==-1)perror("semctlsetvalerror");
arg.val=1;
if(semctl(mutxid,0,SETVAL,arg)==-1)perror("setctlsetvalerror");
//初始化P,V操作
V.sem_num=0;
V.sem_op=1;
V.sem_flg=SEM_UNDO;
P.sem_num=0;
P.sem_op=-1;
P.sem_flg=SEM_UNDO;
//生产者进程
if(fork()==0)
{
inti=0;
while(i<100)
{
semop(emptyid,&P,1);
semop(mutxid,&P,1);
array[*(set)%MAXSEM]=i+1;
printf("Producer%d\n",array[(*set)%MAXSEM]);
(*set)++;
semop(mutxid,&V,1);
semop(fullid,&V,1);
i++;
}//endofwhileinline62
sleep(10);
printf("Producerisover");
exit(0);
}//endofifinline59
else
{
//消费者A进程
if(fork()==0)
{
while
(1)
{
semop(fullid,&P,1);
semop(mutxid,&P,1);
if(*get==100)
break;
*sum+=array[(*get)%MAXSEM];
printf("TheComsumerAGetNumber%d\n",array[(*get)%MAXSEM]);
(*get)++;
if(*get==100)
printf("Thesumis%d\n",*sum);
semop(mutxid,&V,1);
semop(emptyid,&V,1);
sleep
(1);
}//endofwhile
(1)inline82
printf("ConsumerAisover");
exit(0);
}//endofifinline81
else
{//消费者B进程
if(fork()==0)
{
while
(1)
{
semop(fullid,&P,1);
semop(mutxid,&P,1);
if(*get==100)
break;
*sum+=array[(*get)%MAXSEM];
printf("TheComsumerBGetNumber%d\n",array[(*get)%MAXSEM]);
(*get)++;
if(*get==100)
printf("Thesumis%d\n",*sum);
semop(mutxid,&V,1);
semop(emptyid,&V,1);
sleep
(1);
}//endofwhile
(1)inline105
printf("ConsumerBisover");
exit(0);
}//endofifinline103
}//endofelseinline101
}//endofelseinline78
sleep(20);
return0;
}//endofmain
5.运行结果与运行情况
运行截图如下:
6.调试记录:
有三个worning:
7.自我评析和总结:
这次操作系统课程设计,我在设计过程中虽然遇到了困难,但是通过上网查阅资料很好的解决了问题,让我真正理解了Linux内核定时器的本质。
其实这个课程设计是我和同学一起完成的,虽然不是很完美,但是起码能让我们很好的理解了什么是生产者—消费者问题。
让我对互斥问题有了更深的见解。
8.参考文献
[1]《OperatingSystemConcepts(SixthEdition)(操作系统概念)影印版》AbrahamSilberschatz编高等教育出版社2003年
[2]《计算机操作系统教程(第三版)》张尧学编清华大学出版社2001年
[3]《操作系统原理(第三版)》庞丽萍华中科技大学出版社2000年
本科生课程设计成绩评定表
班级:
软件0703 姓名:
学号:
0120710680319
序号
评分项目
满分
实得分
1
学习态度认真、遵守纪律
10
2
设计分析合理性
10
3
设计方案正确性、可行性、创造性
20
4
设计结果正确性
40
5
设计报告的规范性
10
6
设计验收
10
总得分/等级
评语:
注:
最终成绩以五级分制记。
优(90-100分)、良(80-89分)、中(70-79分)、
及格(60-69分)、60分以下为不及格
指导教师签名:
2010年6月15日