燕山大学os课程设计说明书.doc_第1页
燕山大学os课程设计说明书.doc_第2页
燕山大学os课程设计说明书.doc_第3页
燕山大学os课程设计说明书.doc_第4页
燕山大学os课程设计说明书.doc_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

操作系统课设报告1. 概述31.1. 目的31.2. 主要完成的任务31.3. 使用的开发工具31.4. 解决的主要问题32. 使用的基本概念和原理32.1. 线程32.2. 线程的同步42.3. 模态对话框42.4. 原理43. 总体设计43.1. 确定基本的技术路线43.2. 软件的总体结构43.3. 创建的进程和线程54. 详细设计54.1. 利用的进程操作的函数、原语、API54.1.1. 信号量创建函数54.1.2. 互斥对象的创建.54.1.3. 线程创建函数64.1.4. 等待函数64.2. 模块内部的流程和实现算法64.3. 全局变量的声明85. 编码设计95.1. 开发环境的设置和建立95.2. 编译环境的设置95.3. 程序设计时要注意的事项105.4. 主要程序的代码设计及注释105.5. 解决的技术难点、经常犯的错误146. 测试时出现的问题及其解决方法147. 软件使用说明及运行结果147.1. 基本功能147.2. 需要运行的环境157.3. 安装及运行157.4. 操作157.5. 运行结果158. 总结168.1. 操作系统课程设计完成情况168.2. 收获和感受168.3. 经验总结169. 参考文献171. 概述1.1. 目的 通过使用程序设计语言设计一个程序,模拟生产者消费者和搬运者对产品操作的过程。1.2. 主要完成的任务PutMove2Buff1Buff2Buff3GetMove1 图1 Buffer操作 (1) 可以随机产生字符数据,由put操作放入Buff1,buffer中容量单位是字符。 (2) 提供良好图形界面,显示Buffer的操作过程。 (3) 可以设定各Buffer的容量、PUT、GET、Move操作的个数; (4) 可以设定PUT、GET、Move操作的速度; (5) 实时显示每个Buffer中数据的个数和数据的内容,空闲Buffer的空间的个数; (6) 实时显示线程、进程所处于等待(阻塞)状态的个数 (7) 程序运行结束,显示汇总数据: 总的运行时间; Buffer中数据的个数; 已放入BUFFER的数据个数; 已放已取的数据个数; 平均每个buffer中的数据个数。1.3. 使用的开发工具使用MFC在VC+6.0上完成程序的设计。1.4. 解决的主要问题 (1)可以随机产生字符数据。 (2)设计put,get,move的线程。 (3)可以设计buffer的容量,put,get,move的个数。 (4)控制put,get,move的速度。 (5)实时显示buffer的内容。2. 使用的基本概念和原理2.1. 线程线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。2.2. 线程的同步 临界段:临界段对象通过提供所有线程必须共享的对象来控制线程。只有拥有临界段对象的线程才可以访问保护资源(进行临界区操作)。在另一个线程可以获取对象的访问权。用户应用程序可能会使用临界对象来阻止两个线程同时访问共享的资源发文件等。 互斥量:互斥量的工作方式和临界段非常相似,其区别在于互斥量不公保护一个进程内的资源共享,而且还保护系统中进程之间的共享资源。它是通过为互斥量提供一个“互斥量名”来进行进程间资源共享协调的。 事件:事件对象用于给线程传递信号,指示线程中特定的操作可以开始或结束。除非线程已经收到了这个事件信号,否则它将一直处于挂起状态。当事件对象进入其信号状态时,正在等待该事件的线程就可以开始执行。例如,一个应用程序可以通过事件来通知线程它需要的数据已经准备好。经常利用事件进行线程之间的通信。 信号量:信号量与互斥相似,但是互斥只允许在同一时刻一个线程访问它的数据,而信号量允许多个线程在同一时刻访问它的数据。WIN32 不知道哪一个线程拥有信号量,它只保证信号量使用的资源计数正确的设置。2.3. 模态对话框 模态对话框(Modal Dialogue Box,又叫做模式对话框),是指在用户想要对对话框以外的应用程序进行操作时,必须首先对该对话框进行响应。如单击【确定】或【取消】按钮等将该对话框关闭。2.4. 原理 使用信号量作为同步互斥的工具,通过对BUFFER1、BUFFER2的容量,还有控制权设置不同的信号量来协调PUT、GET、MOVE线程,使其同步来实现P、V操作。3. 总体设计3.1. 确定基本的技术路线用MFC设计的,是面向对象的程序。3.2. 软件的总体结构设置模块,设置生产者消费者搬运者的初始值,及其它们的速度。显示模块,实时显示生产者消费者搬运者及buffer的情况变化,还有汇总的情况。生产者消费者搬运者过程演示控制模块,控制开始,停止及退出。 图2 框架图3.3. 创建的进程和线程 (1)DWORD WINAPI ThreadProduct(LPVOID lpParameter);/生产者线程 (2)DWORD WINAPI ThreadConsumer(LPVOID lpParameter);/生产者线程 (3)DWORD WINAPI ThreadMover1(LPVOID lpParameter);/搬运者1线程 (4)DWORD WINAPI ThreadMover2(LPVOID lpParameter);/搬运者2线程 (5)DWORD WINAPI ThreadBuffer1(LPVOID lpParameter);/显示buffer1的线程 (6)DWORD WINAPI ThreadBuffer2(LPVOID lpParameter);/显示buffer2的线程 (7)DWORD WINAPI ThreadBuffer3(LPVOID lpParameter);/显示buffer3的线程 (8)DWORD WINAPI ThreadCount(LPVOID lpParameter);/汇总的线程 (9)DWORD WINAPI Threadtime(LPVOID lpParameter);/时间的线程4. 详细设计4.1. 利用的进程操作的函数、原语、API 4.1.1. 信号量创建函数 HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, / 安全属性指针LONG lInitialCount, / 初始计数LONG lMaximumCount, / 最大计数LPCTSTR lpName / 对象名指针); 该函数创建一个信号量,llnitialCount 是对信号量的初始值,iMaximunCount为信号量的最大值,即信号量在一个范围内有效,例empty=:CreateSemaphore(0,0,M,0);第二个0为empty信号量的初始值,M为信号量的最大值,在这个范围内(0,M)信号量都是有信号的。4.1.2. 互斥对象的创建HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,安全属性结构指针,可为NULL,表示默认安全性BOOL bInitialOwner,/是否占有该互斥量,TRUE:占有,FALSE:不占有LPCTSTR lpName/设置互斥对象的名字);如果一个线程拥有了一个互斥对象后,当该线程运行完成后就要释放该互斥对象,不然其他的线程得不到互斥对象则无法运行。用ReleaseMutex(HWND);操作它的具体作用是每调用它一次将互斥对象的计数器减一,直到减到零为止,此时释放互斥对象,并将互斥对象中的线程id置零。它的使用条件是,互斥对象在哪个线程中被创建,就在哪个线程里面释放。因为调用的时候会检查当前线程的id是不是与互斥对象中保存的id一致,若一致,则此次操作有效,不一致,则无效。4.1.3. 线程创建函数HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes./线程安全属性DWORD dwStackSize,/线程堆栈的初始化大小,等于0时为系统默认的堆栈大小PLTHREAD_START_ROUTINE lpStartAddress,/线程函数LPVOID lpParameter,/线程参数DWORD dwCreationFlags,/创建方式LPDWORD lpThreadId/线程标识符);该函数创建一个线程,如果没有特殊需要除第三个参数外都可设为0,按系统的默认取值对待,主要是第三个参数,它是线程程序的入口,线程序入口的标准形式为 UINT FUNCTION(LPVOID param)线程函数里可以传一个指针做为参数(param),该参数由创建线程函数(CreateThread)里的第四个参数确定。4.1.4. 等待函数 DWORD WaitForSingleObjec( HANDLE hHandle,/对象句柄 DWORD dwMilliseconds/等待的时间,单位为毫秒 )该函数在不同的应用里会有不同的意义,在信号量里应用时主要是判断信号量是否有信号。第二个参数为等待时间,我们通常设为INFINITE,即为无限等待,在等待期间会将线程挂起,直到等待的信号量有信号。4.2. 模块内部的流程和实现算法 设置6个信号量full1、empty1、hMutex1、full2、empty2、hMutex2,full3、empty3,hMutex3它们的含义和初值如下: (1)full1buffer1是否有数据,初值为0; (2)empty1buffer1有空间,初值为M; (3)hMutex1buffer1是否可操作,初值为1; (4)full2buffer2是否有数据,初值为0; (5)empty2buffer2有空间,初值为N; (6)hMutex2buffer2是否可操作,初值为1;(7)full3buffer3是否有数据,初值为0;(8)empty3buffer3有空间,初值为Q;(9)hMutex3buffer3是否可操作,初值为1; 设置三类进程函数,用信号量实现同步互斥,PUT,MOVE,GET算法如下: While()P(empty1); /*判断buff1是否有空间,没有则等待 */ P(hMutex1); /*是否可操作buffer1*/PUT; V(hMutex1); /*设置buff1可操作标志 */ V(full1); /*设置buff1有数据的标志 */ until false Move1 While()P(full1); /*判断buffer1是否有数据*/P(empty2); /*判断buffer2是否有空间*/ P(hMutex1); /*是否可操作buffer1 */P(hMutex2); /*是否可操作buffer2 */MOVE; V(hMutex1); /*设置buffer1可操作标志*/ V(hMutex2); /*设置buffer2可操作标志*/ V(empty1); /*设置buffer1有空间标志*/ V(full2); /*设置buffer2有数据标志*/ until false Move2 While()P(full2); /*判断buffer2是否有数据*/P(empty3); /*判断buffer3是否有空间*/ P(hMutex2); /*是否可操作buffer2 */P(hMutex3); /*是否可操作buffer3*/MOVE; V(hMutex2); /*设置buffer2可操作标志*/ V(hMutex3); /*设置buffer3可操作标志*/ V(empty2); /*设置buffer2有空间标志*/ V(full3); /*设置buffer3有数据标志*/ until false While()P(full3); /*判断buffer3是否有数据,没有则等待 */ P(hMutex3); /*是否可操作buffer3*/GET; V(hMutex3); /*设置buffer3可操作标志 */ V(full3); /*设置buffer3有数据的标志 */ until false4.3. 全局变量的声明 int put_buffer1=0;/放入buffer1的产品个数; int move_buffer1=0;/从buffer1中取走的产品个数; int move_buffer2=0;/从buffer2中取走的产品个数; int get_buffer3=0;/从buffer3中取走的产品个数; int m_time;/记录时间 int buffer1;/buffer1中产品个数 int buffer2;/buffer2中产品个数 int buffer3;/buffer3中产品个数 int consumer;/消费者个数 int product;/生产者个数 int mover;/搬运者一的个数 int mover2;/搬运者二的个数 int producterid=1;/生产者的id号 int moverid1;/搬运者1的id号 int moverid2;/搬运者2的id号 int consumer_id=1;/消费者的id int productid=101;/生产者生产出来的产品的id号 int name_product;/存储随机产品; int ioend=0;/判断用的 int toend=1; int consumerid=101;/消费者消费的产品id号 int move1_consumerid=101;/搬运者搬运的产品的id号 int move2_consumerid=101; int put=1000;/put的速度 int move1=1000;/move1的速度 int move2=1000;/move2的速度 int get=1000;/get的速度 CString getget;/存获取m_list_buffer里面的第0行的字符串; CString move;/存获取m_list_buffer里面的第0行的字符串; CString putput;/存获取m_list_buffer里面的第0行的字符串;5. 编码设计5.1. 开发环境的设置和建立 (1)起动VISUAL C+ 6.0程序 (2)在菜单里选择文件,子菜单里选择新建,弹出新建对话框,如图3所示。 图3.新建工程 (3)在左边的新建选项里选择MFC AppWizardexe选项,右边的project name里填入一个工程名,选择OK按扭。选择默认设置。5.2. 编译环境的设置 在WINDOWS环境下的多线程中,为保证程序的正确性,必须使用用于多线程环境的正确的函数库,在VC+ 6.0开发环境中在菜单工程中设置中进行选择。步骤如下: (1)选择PROJECT菜单中的SETTING.项; (2)在打开的表彰中选择C/C+项; (3)选择CATEGORY中的CODE GENERATION项; (4)在USE RUN-TIME LIBRARY中选择MULTITHREADED; (5)单击OK即可。 此时,在命令行方式下编译选项由ML变为MT,如图4所示。 图4.编译环境5.3. 程序设计时要注意的事项(1)尽量避免全局变量的使用;(2)变量的命名要规范;(3)注意给代码多写注释;(4)注意进行模块化设计,写相应的函数来完成相应的功能。5.4. 主要程序的代码设计及注释 (1)四个主要线程PUT,GET,MOVE1,MOVE2代码实现。DWORD WINAPI ThreadProduct(LPVOID lpParameter)int j=producterid;/用j来标记第几条线程;producterid+;while(toend)Sleep(put);CString str;CString str1;CString str2;WaitForSingleObject(SemaphoreEmpty,INFINITE);WaitForSingleObject(hMutex,INFINITE);put_buffer1+;/放进去一个产品,就加一;srand(unsigned)time(NULL);name_product=(rand()%26)+65;str.Format(%s%d%4d%s,工作者完成,j,put_buffer1,次生产);str1.Format(%s%d%s%c,产品号:,productid+,产品名:,name_product);str2.Format(%s%d%s,线程,j,在运行,其他线程处于阻塞状态);m_list_product-DeleteString(0);m_list_product-DeleteString(0);m_list_product-InsertString(-1,str);m_list_product-InsertString(-1,str1);m_list_product-InsertString(-1,str2);m_list_buffer1-InsertString(-1,str1);Sleep(400);m_list_product-DeleteString(2);ReleaseMutex(hMutex);ReleaseSemaphore(SemaphoreFULL,1,NULL);return 1;DWORD WINAPI ThreadMover1(LPVOID lpParameter)int j=moverid1;moverid1+;while(toend)Sleep(move1);CString str;CString str1;CString str2;WaitForSingleObject(SemaphoreFULL,INFINITE);WaitForSingleObject(SemaphoreEmpty2,INFINITE);WaitForSingleObject(hMutex,INFINITE);WaitForSingleObject(hMutex2,INFINITE);move_buffer1+;/表示从buffer1移出的产品也是移入buffer2的产品个数;str.Format(%s%d%s%4d%s,搬运者,j,buffer1-buffer2,move_buffer1,次搬运);str2.Format(%s%d%s,线程,j,在运行其他线程处于阻塞状态);m_list_buffer1-GetText(0,putput);m_list_move1-DeleteString(0);m_list_move1-DeleteString(0);m_list_move1-InsertString(-1,str);m_list_move1-InsertString(-1,putput);m_list_move1-InsertString(-1,str2);m_list_buffer1-DeleteString(0);m_list_buffer2-InsertString(-1,putput);Sleep(400);m_list_move1-DeleteString(2);ReleaseMutex(hMutex2); ReleaseMutex(hMutex); ReleaseSemaphore(SemaphoreFULL2,1,NULL);ReleaseSemaphore(SemaphoreEmpty,1,NULL);return 1;DWORD WINAPI ThreadMover2(LPVOID lpParameter)int j=moverid2;moverid2+;while(toend)Sleep(move2);CString str;CString str2;WaitForSingleObject(SemaphoreFULL2,INFINITE);WaitForSingleObject(SemaphoreEmpty3,INFINITE);WaitForSingleObject(hMutex2,INFINITE);WaitForSingleObject(hMutex3,INFINITE);move_buffer2+;/表示从buffer2移出的产品也是移入buffer3的产品个数;str.Format(%s%d%s%4d%s,搬运者,j,buffer2-buffer3,move_buffer2,次搬运);str2.Format(%s%d%s,线程,j,在运行其他线程处于阻塞状态);m_list_buffer2-GetText(0,move);m_list_move2-DeleteString(0);m_list_move2-DeleteString(0);m_list_move2-InsertString(-1,str);m_list_move2-InsertString(-1,move);m_list_move2-InsertString(-1,str2);m_list_buffer2-DeleteString(0);m_list_buffer3-InsertString(-1,move);Sleep(400);m_list_move2-DeleteString(2);ReleaseMutex(hMutex3); ReleaseMutex(hMutex2); ReleaseSemaphore(SemaphoreFULL3,1,NULL);ReleaseSemaphore(SemaphoreEmpty2,1,NULL);return 1;DWORD WINAPI ThreadConsumer(LPVOID lpParameter)int j=consumer_id;consumer_id+;while(toend)Sleep(get);CString str;CString str1;CString str2;WaitForSingleObject(SemaphoreFULL3,INFINITE);WaitForSingleObject(hMutex3,INFINITE);get_buffer3+;str.Format(%s%d%s,本次生产完成:,get_buffer3,次消费);str2.Format(%s%d%s,线程,j,在运行其他线程处于阻塞状态);m_list_buffer3-GetText(0,getget);m_list_buffer3-DeleteString(0);m_list_consumer-DeleteString(0);m_list_consumer-DeleteString(0);m_list_consumer-InsertString(-1,str);m_list_consumer-InsertString(-1,getget);m_list_consumer-InsertString(-1,str2);Sleep(400);m_list_consumer-DeleteString(2);ReleaseMutex(hMutex3); ReleaseSemaphore(SemaphoreEmpty3,1,NULL);return 1;5.5. 解决的技术难点、经常犯的错误 (1)不了解MFC已经封装好的函数的功能,有时候都不会调用,要通过MSDN来查,或者通过百度来查。(2)控件不太会使用,刚开始的时候还不知道如何绑定控件和变量。(3)全局变量和局部变量的使用不清楚,有时候造成一些错误。6. 测试时出现的问题及其解决方法 (1)局部变量的运用:有一次有一个局部变量写错了,把j写成了i,结果导致程序运行不下去,我通过单步跟踪,跟踪程序的运行,最后修改了这个局部变量。 (2)随机生产的产品如何记录:并非记录全部产生的变量,我在生产者线程中用一个局部变量记录随机产生的字符产品,然后将其放入buffer1,搬运者是通过获取buffer里的第一个字符就是所要搬运的产品。 (3)buffer的内的内容实时显示是通过在定义了buffer

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论