多道程序缓冲区协调操作操作系统报告.docx
《多道程序缓冲区协调操作操作系统报告.docx》由会员分享,可在线阅读,更多相关《多道程序缓冲区协调操作操作系统报告.docx(13页珍藏版)》请在冰点文库上搜索。
多道程序缓冲区协调操作操作系统报告
苏州科技学院天平学院
操作系统课程设计 报告
--多道程序缓冲区协调操作
专业年级
计算机工程2010
班 级
计算机工程1022
计算机工程1022
学 号
1032107209
1032107202
姓 名
刘志愿
金志献
成 绩
指导教师
陆卫忠
2012年7月 4 日
任务分配情况
姓名
承担的任务
金志献
编写主函数编译执行程序并修改
刘志愿
协助修改程序编写报告
多道程序缓冲区协调操作
一.概述
1.目的:
(1)了解提出信号量的背景
(2)掌握信号量的基本概念及PV操作的原理
(3)进一步熟悉信号量解决的经典问题
(4)利用信号量的原理实现不同操作系统下同步互斥问题
2.主要完成的任务:
有10个Put操作要不断循环地向InBuffer送数据,有一个Move操作要不断地将InBuffer的数据取到OutBuffer,有20个GET操作要不断地从OutBuff中取数据。
InBuffer的容量是10,OutBuff的容量是20,Put、Move、Get每次操作一个数据,为了在操作的过程中要保证数据不丢失,每个Buffer每次只能接受一个Put或一个Move或一个Get,多个操作不能同时操作同一Buffer(即需要互斥操作)。
设计一个多道程序完成上述操作。
试用P、V原语(或Wait、Signal)协调Put、Move、Get的操作,并说明每个信号量的含义、初值和值的范围。
3.使用的开发工具:
VMwareWorkstation,RedHatLinux2.4.20-8
4.解决的主要问题:
需求分析利用信号量实现缓冲区管理临界区协调问题。
解决由于进程线程共享内存而出现的与时间有关的错误。
二.使用的基本概念和原理
2.1.信号量:
为解决多进程线程同步与互斥问题,让两个或多个多道进程线程通过特殊的变量展开交互。
2.2.线程:
是进程的一个实体,是进程上下文中执行的代码序列,是被系统调度的基本单元。
2.3.进程:
进程是正在运行的程序实体,并且包括这个运行的程序中占据的所有系统资源。
2.4.互斥与同步:
进程的同步与互斥是指进程在推进时的相互制约关系。
进程同步:
它主要源于进程合作,是进程间共同完成一项任务时直接发生相互作用的关系。
进程互斥:
它主要源于资源共享,是进程之间的间接制约关系。
三.总体设计
生产者—消费者问题是相互合作的进程关系的一种抽象,可以利用信号量机制来解决生产者—消费者问题,利用互斥信号量mutex实现进程对缓冲池的互斥使用。
对信号量的操作只能通过两个原子操作:
Wait(s)和Signal(s).Wait(s)是等待信号的操作,进行S=S-1操作;Signal(s)是发送信号的操作,进行S=S+1操作。
wait若s-1后仍大于或等于零,则进程继续执行;若s-1后小于零,则该进程被阻塞后进入与该信号相对应的队列中,然后转进程调度;若相加结果大于或等于零,则从该信号的等待队列中唤醒一等待进程,然后再返回原进程继续执行或转进程调度
如下图所示,有10个PUT(相当于生产者)操作要不断循环地向Buffer1送数据,有一个Move(相当于搬运者)操作要不断地将Buffer1的数据取到Buffer2,有20个GET(相当于消费者)操作要不断地从Buff2中取数据。
BUFF1是10,BUFF2的容量是20,PUT、MOVE、GET每次操作一个数据,为了在操作的过程中要保证数据不丢失,每个Buffer每次只能接受一个PUT或一个Move或一个Get,多个操作不能同时操作同一BUFFER。
设计一个多道程序完成上述操作。
试用P、V原语协调PUT、MOVE、GET的操作,并说明每个信号量的含义、初值和值的范围。
设计总体流程图如下:
四.详细设计
4.1线程规划
我们创建三类线程:
(1)PUT线程(往BUFFER1里放数据,相当于生产者)。
(2)MOVE线程(从BUFFER1里取数据并放到BUFFER2里,相当于搬运者)。
(3)GET线程(从BUFFER2里取数据,相当于消费者)。
每类线程可由用户自行设定线程的个数。
4.2信号量的设置
需要设置六个信号量full1empty1buff1full2empty2buff2。
各信号量含义及初值如下:
full1表示buffer1是否有数据,初值为0;
empty1表示buffer1是否有空间,初值为m;
buff1表示buffer1是否可操作,初值为1;
full2表示buffer2是否有数据,初值为0;
empty2表示buffer2是否有空间,初值为n;
buff2表示buffer2是否可操作,初值为1。
五.编码设计
1.开发环境为Linux,我们在进入RedHatLinux后输入startx进入图形界面,在任务菜单里可以寻找终端,即可进行代码编写与执行。
2.程序源代码如下
/****************定义头文件****************/
#include
#include
#include
#include
#include
#include
#include
/****************定义头变量****************/
sem_tiFull,iEmpty;
sem_toFull,oEmpty;
intiIn=0,iOut=0,oIn=0,oOut=0;
sem_tsem1,sem2;
charinBuffer[10];
charoutBuffer[20];
intdata1,data2,data3;
voidput(void*arg);
voidmove(void*arg);
voidget(void*arg);
/****************mian函数****************/
main(intargc,char*argv[])
{
inti,j;
int*task1[10];
int*task2[20];
pthread_tid1[10],id2,id3[20];
intret;
/*初始化信号量imutex为1*/
ret=sem_init(&sem1,0,1);
if(ret!
=0)
perror("sem_init");
/*初始化信号量omutex为1*/
ret=sem_init(&sem2,0,1);
if(ret!
=0)
perror("sem_init");
/*初始化信号量iFull为1*/
ret=sem_init(&iFull,0,0);
if(ret!
=0)
perror("sem_init");
/*初始化信号量iEmpty为10*/
ret=sem_init(&iEmpty,0,10);
if(ret!
=0)
perror("sem_init");
/*初始化信号量oFull为0*/
ret=sem_init(&oFull,0,0);
if(ret!
=0)
perror("sem_init");
/*初始化信号量oEmpty为20*/
ret=sem_init(&oEmpty,0,20);
if(ret!
=0)
perror("sem_init");
/*创建三个线程*/
//move线程
ret=pthread_create(&id2,NULL,(void*)move,NULL);
if(ret!
=0)
perror("pthreadthreadmoveerror.");
//put线程
for(i=0;i<10;i++)
{
task1[i]=(int*)malloc(sizeof(int));
*task1[i]=i;
ret=pthread_create(&id1[i],NULL,(void*)put,(void*)task1[i]);
if(ret!
=0)
perror("pthreadthreadputerror.");
}
//get线程
for(j=0;j<20;j++)
{
task2[j]=(int*)malloc(sizeof(int));
*task2[j]=j;
ret=pthread_create(&id3[j],NULL,(void*)get,(void*)task2[j]);
if(ret!
=0)
perror("pthreadthreadgeterror.");
}
for(i=0;i<10;i++)pthread_join(id1[i],NULL);
pthread_join(id2,NULL);
for(j=0;j<20;j++)pthread_join(id3[j],NULL);
exit(0);
}
/****************put操作线程函数****************/
voidput(void*arg)
{
inti;
int*threadid1;
threadid1=(int*)arg;
srand(time(NULL));
while
(1)
{
sleep
(1);
data1=rand()%128;
/*信号量减一,P操作*/
sem_wait(&iEmpty);
sem_wait(&sem1);
sleep
(1);
printf("put[%d]:
iIn=%d,\nThedataputintotheinBufferis:
%d\n",*threadid1,iIn,data1);
inBuffer[iIn]=data1;
iIn=(iIn+1)%10;
/*信号量加一,V操作*/
sem_post(&sem1);
sem_post(&iFull);
sleep
(2);
}
}
/****************move操作线程函数****************/
voidmove(void*arg)
{
intret;
while
(1)
{
/*move操作将数据取出inBuffer缓冲区*/
sem_wait(&iFull);
sem_wait(&sem1);
sleep
(1);
data2=inBuffer[iOut];
printf("move:
iOut=%d,\nThedatagetoutoftheinBufferis:
%d\n",iOut,data2);
iOut=(iOut+1)%10;
sem_post(&sem1);
sem_post(&iEmpty);
sleep
(1);
/*move操作将数据放入outBuffer缓冲区*/
sem_wait(&oEmpty);
sem_wait(&sem2);
sleep
(1);
outBuffer[oIn]=data2;
printf("move:
oIn=%d,\nThedataputintotheoutBufferis:
%d\n",oIn,data2);
oIn=(oIn+1)%20;
sem_post(&sem2);
sem_post(&oFull);
sleep
(1);
}
}
/****************get操作线程函数****************/
voidget(void*arg)
{
intret;
int*threadid2;
threadid2=(int*)arg;
while
(1)
{
sem_wait(&oFull);
sem_wait(&sem2);
sleep
(1);
data3=outBuffer[oOut];
printf("get[%d]:
oOut=%d,\nThedatagetoutoftheoutBufferis:
%d\n",*threadid2,oOut,data3);
oOut=(oOut+1)%20;
sem_post(&sem2);
sem_post(&oEmpty);
sleep
(1);
}
}
六.测试时出现过的问题及解决方法
1.一开始写程序时无从下手,后来经过老师指点将本程序的P.V原语写出,程序就可以按照P.V原语的顺序往下写。
2.一开始不明白程序的线程操作上锁与解锁的含义,后来经老师指导得知线程互斥与同步就是信号量的互斥与同步,创建信号量就可以表示出线程间的关系。
3.出现段错误,后改成输入的数据有随机数生成函数产生即解决此问题。
一开始不明白程序的线程操作上锁与解锁的含义,后来经老师指导得知线程互斥与同步就是信号量的互斥与同步,创建信号量就可以表示出线程间的关系。
4.编译时为出错,但在执行时出现段错误,后改成输入的数据有随机数生成函数产生即解决此问题。
七.实验结果
实验结果如下:
八.总结
本软件利用RedHatLinux-VMware实现多线程的同步,用户可以直接观察多线程的运行,协调,并且可以设置线程的个数,缓冲区的容量,以及线程的速度。
整个程序的设计过程中出现了很多问题,比如在设计过程中该设计几个类,各个类该完成什么样的功能,如何实现各个功能,一个类如何调用另一个类中的变量、如何处理事件等等许多问题,在几天的认真思考后,一一解决了,做的课题虽然不是很庞大,但却很锻炼人,在代码设计过程中,对MFC面向对象的思想有了更深入的了解,程序中用到了很多操作系统的思想,如P,V操作,信号量的互斥与实现,线程的概念,对这些概念理解的更加透彻了,几天的设计过程中也看到了自己的不足,如RedHatLinux-VMware不能熟练运用,在以后的学习中应更加努力、这次课程设计虽然只有短短的几天,但却为我们未来做毕业设计及开发软件打下了基础,意义重大。
从这次课程设计中我们认识到,在开始写代码前,一定要有个整体的规划,如设计几个类,每个类能完成什么样的功能,应该设计几个变量,几个方法,各个方法能完成的功能等等,如果没有整体的规划,在代码编写过程中就无从下手,或者写了一半发现这样写不能实现要求的功能。
在写代码时,最好遵循编程规范,否则代码的修改与维护会很困难,在和别人共同编写程序时更应该注意这一点。
八.参考文献
[1]汤小丹,梁红兵,哲凤屏,汤子瀛.计算机操作系统.西安:
西安电子科技大学出版社,2007.