1、操作系统课程设计目 录第一章 课程设计目的和要求11.1 课程设计目的11.2 课程设计要求1第二章 课程设计任务内容22.1课程设计任务22.2课程设计内容2第三章 详细设计说明33.1问题描述33.2模块设计33.3程序流程图43.4算法与数据结构53.4.1数据结构53.4.2算法描述53.4.3算法流程图6第四章 软件使用说明104.1系统开发与运行环境104.2系统的运行说明104.3 运行结果10第五章 课程设计心得体会15附录1:参考文献16附录2:程序清单171第一章 课程设计目的和要求1.1 课程设计目的操作系统是计算机系统的核心和灵魂,是计算机系统必不可少的组成部分,也是计
2、算机专业教学的重要内容。该课程概念众多、内容抽象、灵活性与综合性强,不但需要理解操作系统的概念和原理,还需要加强操作系统实验,上机进行编程实践,故进行此次课程设计,使我们更好地掌握操作系统的精髓,真正做到深刻理解和融会贯通。 操作系统课程设计是本课程重要的实践教学环节。课程设计的目的,一方面使学生更透彻地理解操作系统的基本概念和原理,使之由抽象到具体;另一方面,通过课程设计加强学生的实验手段与实践技能,培养学生独立分析问题、解决问题、应用知识的能力和创新精神。此次课程设计给学生更多自行设计、自主实验的机会,充分放手让学生真正培养学生的实践动手能力,全面提高学生的综合素质。本次课程设计的题目为读
3、者写者同步问题的实现,在熟练掌握进程同步原理的基础上,利用C程序设计语言在windows操作系统下模拟实现读者写者同步问题的功能,一方面加深对原理的理解,另一方面提高根据已有原理通过编程解决实际问题的能力,为进行系统软件开发和针对实际问题提出高效的软件解决方案打下基础。1.2 课程设计要求在深入理解操作系统基本原理的基础上,对于选定的题目以小组为单位,先确定设计方案,设计系统的数据结构和程序结构,设计每个模块的处理流程。要求设计合理,编程序实现系统,要求实现可视化的运行界面,界面应清楚地反映出系统的运行结果,确定测试方案,对系统进程测试,运行系统并要通过验收,讲解运行结果,说明系统的特色和创新
4、之处,并提交课程设计报告。第二章 课程设计任务内容2.1课程设计任务要求完成的主要任务: (包括课程设计工作量及其技术要求,以及说明书撰写等具体要求)1技术要求: 1)为每个读者写者产生一个线程,设计正确的同步算法; 2)读者应有3个以上,写者应有有两个以上; 3) 必须包含读者优先唤醒和写者优先唤醒两种算法。2设计说明书内容要求: 1)设计题目与要求; 2)总的设计思想及系统平台、语言、工具等; 3)数据结构与模块说明(功能与流程图); 4)运行结果与运行情况。2.2课程设计内容 本次课程设计是实现读者写者的同步与互斥问题,要求实现读者与读者可以共享资源,读者与写者互斥,写者与写者互斥,要求
5、编写出完整的代码,并截取运行结果截图。 第三章 详细设计说明3.1问题描述 所谓读者写着问题,是指保证一个writer进程必须与其他进程互斥地访问共享对象的同步问题。读者写者问题可以这样的描述,有一群写者和一群读者,写者在写同一本书,读者也在读这本书,多个读者可以同时读这本书,但是,只能有一个写者在写书。为实现读写同步,需要使用信号量机制。信号量机制是支持多道程序的并发操作系统设计中解决资源共享时进程间的同步与互斥的重要机制,而读者写者则是这一机制的一个经典范例。对利用信号量来解决读者写者问题的描述如下: 1)写-写互斥,即不能有两个写者同时进行写操作; 2)读-写互斥,即不能同时有一个读者在
6、读,同时却有一个写者在写;3)读读允许,即可以有2个以上的读者同时读。 本次课程设计中,在处理读者写者等待队列的请求时,用到了两种唤醒进程算法:读者优先唤醒算法和写者优先唤醒算法。 读优先:当一个读者与若干写者同时处于等待队列中时,并且此时并无写操作进行时,读者优先进行读。 写优先:当一个读者与若干写者同时处于等待队列中时,并且此时并无写操作进行时,写者优先进行写。3.2模块设计1. 程序由三部分组成:1) 主程序:显示主菜单,调用各个子菜单;2) 读者优先唤醒:写者释放资源时,优先唤醒等待队列中的读进程;3) 写者优先唤醒:写者释放资源时,优先唤醒等待队列中的写进程。 主程序读者优先唤醒写者
7、优先唤醒 退 出 图3-1模块划分图3.3程序流程图 结 束 读者优先唤醒 开始显示主菜单输入choiceChoice=1?Choice=2?Choice=3? 写者优先唤醒 退出NNNYYY图3-2为本次课程设计的程序流程图,其中choice为一整型变量,由使用者通过键盘输入: 图3-2程序流程图3.4算法与数据结构3.4.1数据结构1. 定义一个结构体,用来存放读者等待队列,其元素为用来存放读进程的数组reader200,用来指示等待队列中读进程个数的整型变量index:struct rqueue int readers200;int index;rq;2. 定义另一个结构体,用来存放写者
8、等待队列,其元素为用来存放写进程的数组writers200;用来指示等待队列中写进程个数的整型变量index:struct wqueue int writers200;int index;wq;3.4.2算法描述1. 定义一个数据缓存buffer及用于实现同步互斥的信号量w。2. 定义一个读者函数:1) 当有写者在占用buffer时,读者应该等待,直到写者不再使用该buffer;2) 当有其他读者在占用buffer时,读者可对buffer进行读取操作;3) 当buffer中有数据时,则从其中读取一个数据,并显示然后退出;4) 当buffer中没有数据时,应等待,直到buffer中有数据可读,用
9、变量sign指示,为1时才能读;为0时需要等待写者写数据。3. 定义一个写者函数:1) 当有读者在占用buffer时,写者应该等待,直到所有的读者都退出为止;2) 当有其他写者占用buffer时,该写者应该等待,直到占用buffer的写者退出为止;3) 当buffer有空闲时,写者应该在buffer中写入一个数据并退出。4. 定义主函数,在其中可以任意创建读者与写者。 可根据用户输入创建读者或写者进程(线程)。3.4.3 算法流程图1) 读操作算法流程图如图3-3所示:Y 开 始Rcount=0? w=1? sign=1? W=0;rcount+; 进行读等待写者写内容;并加入到读者唤醒队列;
10、Rq.index+; 结束YYNNN 图3-3读者算法流程图注:Rcount表示正在进行读操作的数目;w表示一个信号量,为1时表示无进程操作,缓冲区空闲,为0时表示有进程占用;sign表示缓冲区是否有数写入,只有缓冲区中有数才能进行读操作,为1表示有数,为0表示没有;Rq.index表示读操作等待唤醒队列进程数;2) 写操作算法流程图如图3-4所示: 开 始 W=1? W-;进行写;加入写唤醒队列Wq.index+; 结束NY 图3-4写者算法流程图注:w含义同上;Wq.index表示写操作等待唤醒队列进程数。3) 读者优先唤醒算法流程图如图3-5所示:读者优先唤醒是指当写者释放其占有的资源时
11、,当读者和写者同时有进程等待,优先处理读进程。图3-5注:Rcount.w.Wq.index含义同上;reader_wait是布尔型变量,为真时表示有读者等待,反之没有读者进程等待。4) 写者优先唤醒算法流程图如图3-6所示:写者优先唤醒是指当写进程释放其占有资源时,当读者和写者同时有进程等待,优先处理写进程。图3-6注:Rcount,w,Wq.index含义同上;write_wait是一个布尔型变量,为真时表示有写进程等待,反之没有。NNYNNYYYYWq.index=0? 处理队列首部的写进程N!reader_wait? 开始 Rcount=0?reader_wait=false;w=1;
12、 结束当前写进程Rq.index=0? reader_wait=true; W=0;处理读进程Wq.index!=0? Rcount=0; W=1;处理写进程 W=0; 结束 图3-5读者优先唤醒算法流程图YNNYYYNNY 开始 Rcount=0?write_wait=false;w=1; 结束当前写进程Wq.index=0? write_wait=true; W=0;依次处理写进程Wq.index!=0? Rcount=0; W=1;处理写进程 W=0;!write_wait?Rq.index=0? 处理读进程; w=0 结束N 图3-6 写者优先唤醒算法流程图第四章 软件使用说明4.1系
13、统开发与运行环境 代码实现:C语言程序开发工具:Mcrosoft Visual C + 6.0 运行环境:windows 7 4.2系统的运行说明对读者写者问题系统的运行说明如下:按照显示菜单说明,输入数字对菜单进行选择,一个菜单即是一个功能实现,可以实现读者写者进程同步与互斥问题。4.3 运行结果1. 系统主菜单及读者优先唤醒子菜单,按菜单提示选择1是读者优先唤醒算法,运行结果如图4-1所示: 图4-1主菜单及子菜单2. 在子菜单中选择1创建读进程,由于此之前并无写者向缓冲区中写数,所以缓冲区为空,此时不可读,将读者加入到等待唤醒队列,读者队列数目加1,运行结果如图4-2所示: 图4-2 创
14、建读进程3. 在子菜单中选择2创建写进程1,由于并无进程占用缓冲区,所以写者1不必等待可以直接写数,运行结果如图4-3所示: 图4-3 创建写进程4. 在子菜单中选择1创建读者进程,由于已有写进程占用所以将读者进程加入到读者等待唤醒队列;选择创建写者进程2,由于写者与写者互斥,将写者2加入到写者等待唤醒队列,运行结果如图4-4所示: 图 4-4创建读进程和写进程5. 选择3写者1释放资源,由于此为读者优先唤醒算法,所以优先唤醒读者,进行读进程操作,运行结果如图4-5所示: 图 4-5写者释放占有资源优先唤醒读者6. 选择1创建读进程,读者与读者之间不互斥,所以不必等待;选择2创建写进程3,由于
15、读进程占用资源,所以写者必须等待,将写者加入等待队列,运行结果如图4-6所示: 图 4-6 创建读进程和写进程7. 选择3读者释放资源,写者2被唤醒进行写操作,运行结果如图4-7所示: 图 4-7 读者释放占有资源8. 返回到主菜单并选择写者优先唤醒算法,运行结果如图4-8所示: 图 4-8 写者优先唤醒算法9. 选择3释放当前进程,等待队列中的写者唤醒,运行结果如图4-9所示: 图 4-9 释放写者2,写者3占有资源10. 创建两个读进程和一个写者进程,由于写者3占有资源,所以它们都要加入各自等待唤醒队列中,运行结果如图4-10所示: 图4-10 创建读进程和写进程11. 释放当前写者占有资
16、源,由于本算法使用的是写者优先唤醒算法,所以写者4优先被唤醒占用资源,进行写操作,读者进程依然等待,运行结果如图4-11所示: 图4-11写者释放资源优先唤醒等待队列中的写者第五章 课程设计心得体会 三周的课程设计结束了,这次课程设计是操作系统中读者与写者问题。通过课程设计我懂得了读者与写者的一些简单算法的实现,掌握了用高级语言编写和调试程序的方法,加深了对读者写者问题概念及算法的理解,并且加深了对进程同步算法的理解。同时,在这次课程设计中,也暴露出一些问题,比如动手之前的构思是非常的完美,本来以为会一气呵成的顺利完成任务,可是正是需要动手做得时候却是那么困难,尤其是编写代码的时候,编完运行老
17、是出错,然后改正,还是出错,总是在那些细节上出错,问题虽然不大,但就是不能运行。所以,平时还是要多动手,注意要认真细心。最后,感谢老师对我的学习的指导!附录1:参考文献1 胡志刚,谭长庚等,计算机操作系统,中南大学出版社2005年2 罗宇,邹鹏等,操作系统(第二版),电子工业出版社2007年4月3 汤子瀛,哲风屏,汤小冉等,计算机操作系统,西安电子科技大学出社,2001年8月4 张尧学,史美林,计算机操作系统课程,清华大学出版社,2000年5 庞丽萍,操作系统原理,华中理工大学出版社,2000年6 马季兰等Linux操作系统,电子工业出版社2002年7 任爱华,李鹏,刘方毅,操作系统实验指导,
18、清华大学出版社,2004年8 谭浩强著.C程序设计,清华大学出版社,1999年12月第2版9 谭浩强著.C+程序设计实践指导,清华大学出版社,2005年7月底1版10【美】D.C.Malik:C+编程从问题分析到程序设计,电子工业出版社,2003年7月第一版附录2:程序清单源代码:#include#includeint rcount=0; /正在读的读者数量int wcount=0; /写者队列中等待写操作的写者数量int read_id=0; /读进程号int write_id=0; /写进程号int w=1; /读写互斥信号量;int choice; /用户选择读者优先或者写者优先int
19、sign=0; /标识缓冲区是否为空,0表示空,1表示不为空void WFwakeup();void RFwakeup();struct rqueue /读者等待队列int readers200;int index;rq;struct wqueue /写者等待队列int writers200;int index;wq;/*void first() /初始化int i;rq.index = 0;wq.index = 0;for(i = 0;i20;i+)rq.readersi = 0;wq.writersi = 0;*/*读进程读操作void read()int i = 0;read_id+;i
20、f(rcount = 0) /当前没有读进程在读:可能有写进程在写,也可能CPU空闲if(w=1) /如果CPU空闲,读者拿到获得cpuw-; /相当于一个P操作rcount+;if(sign =0)if(choice = 1)rq.readersrq.index+=read_id; /将读者进程加入等待队列RFwakeup();return;elserq.readersrq.index+=read_id; /将读者进程加入等待队列WFwakeup();return;/ifprintf(读者%d正在读n,read_id);/ifelse /写者线程正在执行printf(!有写者在写不能读!n)
21、;rq.readersrq.index+=read_id; /将读者进程加入等待队列/else/ifelse /rcount !=1 则知道当前已经有读者在读,读读不互斥,则这个读者可以直接进来了读printf(读者%d正在读n,read_id);/else/*写进程写操作void write()write_id+;if(w = 0)if(rcount != 0 ) /有读者进程在执行printf(!有读者在读不能写!n);wq.writerswq.index+=write_id; /将写者进程加入等待队列wcount+;return;if(rcount = 0 ) /rcount = 0则当
22、前无读者,但w = 0,所以有写者在写printf(!有写者在写不能写!n);wq.writerswq.index+=write_id; /将写者进程加入等待队列wcount+;return;if(w = 1)w-;printf(写者%d正在写n,write_id);sign=1;/if/*读者优先时唤醒进程void RFwakeup()int i = 0;int j = 0;int m;m = rq.index;/n = wq.index;if(rcount = 0) /当前无读进程,是写者在写停止运行写进程bool reader_wait=false; w=1;printf(写者已经写完n
23、);sign = 1; /缓冲区中已经有内容要置1for(i=0;i=m;i+) /index为当前读者队列中的等待进程数if(rq.readersi!=0)reader_wait=true; /确实有读者在等待printf(等待的读者%d正在读n,rq.readersi);w = 0;rq.readersi=0;rcount+;rq.index-;/if/forif(!reader_wait) /没有读者等待,看是否有写者等待for(int i=0;i=wq.index;i+) /检查写者等待队列if(wq.writersi!=0)w = 0;printf(等待的写者%d正在写n,wq.wr
24、itersi);wq.writersi=0;wcount-;break;/if/for/if/ifelse /若rcount != 0则读者正在读,停止读者进程,此时若有等待必为写者rcount=0;w = 1;if(sign = 0)printf(缓冲区空,等待写者n);return;elseprintf(读者已经读完n);for(int i=0;i=wq.index;i+) /检查写者等待队列if(wq.writersi!=0)w = 0;printf(等待的写者%d正在写n,wq.writersi);wq.writersi=0;wcount-;break;/if/for/else/els
25、e/*写者优先唤醒void WFwakeup()int i = 0;int j = 0;int m;m = rq.index;/n = wq.index;if(rcount = 0) /当前无读进程,是写者在写则停止运行写进程bool writer_wait=false; w=1;printf(写者已经写完n);sign = 1; /缓冲区已经有内容sign要置1for(i=0;i=wq.index;i+) /index为当前写者队列中的等待进程数 if(wq.writersi!=0)writer_wait=true; /确实有写者在等待printf(等待的写者%d正在写n ,wq.write
26、rsi);w = 0;wq.writersi=0;wcount-;break;if(!writer_wait) /没有写者等待,看是否有读 者等待for(int i=0;i=m;i+) /检查读者者等待队列if(rq.readersi!=0)w = 0;printf(等待的读者%d正在读n,rq.readersi);rq.readersi=0;rcount+;/if/for/if/ifelse /rcount != 0有读者正在读,则停止读;此时若有等待必为写者rcount=0;w = 1;printf(读者已经读完n);for(int i=0;i=wq.index;i+) /检查写者等待队列
27、if(wq.writersi!=0)w = 0;printf(等待的写者%d正在写n,wq.writersi);wq.writersi=0;wcount-;break;/if/forvoid menu1()void menu();char i;printf( 1-创建读者进程n 2-创建写者进程n 3-结束当前执行的进程n 4-返回主菜单n);printf(*n);doprintf(当前队列中有读者: %d个 写者: %d个n,rq.index,wcount);printf(*n);printf( 请输入你的选择:);scanf(%s,&i);switch(i)case 1:read();br
28、eak;case 2:write();break;case 3:RFwakeup();break;case 4:menu();default:printf(输入错误请重新输入:);while(true);void menu2()void menu();char i;printf( 1-创建读者进程n 2-创建写者进程n 3-结束当前执行的进程n 4-返回主菜单n);printf(*n);doprintf(当前队列中有读者: %d个 写者: %d个n,rq.index,wcount);printf(*n);printf( 请输入你的选择:);scanf(%s,&i);switch(i)case
29、1:read();break;case 2:write();break;case 3:WFwakeup();break;case 4:menu();default:printf(输入错误请重新输入:);while(true);void main()void menu();menu();void menu()printf( 读者写着问题 n);printf(*n);printf(1.读者优先唤醒n2.写者优先唤醒n3.退出.n);printf(请输入你选择的优先唤醒算法:);scanf(%d,&choice);while(1)if(choice = 1)menu1();if(choice = 2)menu2();if(choice = 3)exit(0);if(choice != 1 & choice != 2 & choice != 3)printf(输入错误请重新输入:);scanf(%d,&choice);22