欢迎来到三一办公! | 帮助中心 三一办公31ppt.com(应用文档模板下载平台)
三一办公
全部分类
  • 办公文档>
  • PPT模板>
  • 建筑/施工/环境>
  • 毕业设计>
  • 工程图纸>
  • 教育教学>
  • 素材源码>
  • 生活休闲>
  • 临时分类>
  • ImageVerifierCode 换一换
    首页 三一办公 > 资源分类 > DOC文档下载  

    中南大学 操作系统实验报告课程设计报告.doc

    • 资源ID:4193410       资源大小:391.50KB        全文页数:48页
    • 资源格式: DOC        下载积分:8金币
    快捷下载 游客一键下载
    会员登录下载
    三方登录下载: 微信开放平台登录 QQ登录  
    下载资源需要8金币
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    中南大学 操作系统实验报告课程设计报告.doc

    操作系统实验报告界面设计l 菜单菜单包括菜单栏,菜单,菜单项,一个菜单栏可以包括N个菜单,一个菜单可以包括菜单项。C语言设计菜单的思想是用双向链表,先保存绘图区的内容,再在上面画菜单。l 菜单结构图菜单栏菜单1菜单2菜单n.尾指针头指针当前指向菜单菜单项1菜单项2。菜单项n头指针其他菜单项结构类似结尾指针l 数据结构1. 菜单栏:typedef struct menubar_sint number,x,y,barheight,baritemwidth;/*number用来记录菜单项的数目,x,y用来记录菜单栏在屏幕上的位置,barheight用来控制菜单栏的高度,baritemwidth用来控制每项菜单的宽度*/struct menu_s *mhead; /*指向第一个菜单*/struct menu_s *mtail; /*指向最后一个菜单*/struct menu_s *mpoint; /*当用户按下左右箭头时用来记录指向那个菜单,初始指向mhead*/void (* docommand)(); /*菜单时间的处理函数*/MenuBar;2. 菜单:typedef struct menu_sint number; /*菜单是菜单栏中的第几项*/int subwidth; /*菜单项的宽度*/int subcount; /*菜单项的数目*/char *content; /*菜单显示的字符串/struct menu_s *next; /*指向下一个菜单,如果是结尾菜单,则为NULL*/struct menu_s *before; /*指向前一个菜单,如果是头菜单,则为NULL*/struct submenu_s *sub; /*指向当前激活的菜单项*/struct submenu_s *head; /*指向第一个菜单项*/struct submenu_s *tail; /*指向最后一个菜单项*/Menu;3. 菜单项:typedef struct submenu_sint number; /*菜单项是菜单中的第几项*/int isactive; /*是否激活*/char *content; /*显示的字符串*/struct submenu_s *next; /*指向下一个菜单项*/struct submenu_s *before; /*指向前一个菜单项*/submenu;l 函数实现1. 菜单构造函数/*该函数的功能主要是根据指定的menutitle字符串,往菜单栏中添加一项菜单*/void addmenu(char *menutitle)if(Mb=NULL)/*如果Mb(全局MenuBar类型的变量)为NULL,说明没有初始化菜单栏,要初始化*/if(Mb=(MenuBar *)malloc(sizeof(MenuBar)=NULL)doerror("System error");Mb->number=0; /*菜单栏中菜单数目为0*/Mb->mpoint=Mb->mhead=Mb->mtail=NULL;Mb->x=0;Mb->y=0; /*位置于屏幕上(0,0)*/Mb->barheight=18; /*菜单栏高度为18*/Mb->baritemwidth=100; /*每项菜单的宽度为100*/Mb->docommand=docommand; /*设置事件处理函数为docommand()*/if(Mb->mtail=NULL) /*如果Mb->mtail为NULL,说明要先构造Mb->mhead*/if(Mb->mhead=(Menu *)malloc(sizeof(Menu)=NULL)doerror("System error");Mb->mhead->before=NULL;Mb->mtail=Mb->mhead;else if(Mb->mtail->next=(Menu *)malloc(sizeof(Menu)=NULL)doerror("System error");Mb->mtail->next->before=Mb->mtail;Mb->mtail=Mb->mtail->next;Mb->mtail->number=Mb->number; /*当前添加进去的菜单位置,下面有Mb->number的自加*/Mb->mtail->subwidth=0; /*菜单项的宽度为0*/Mb->mtail->subcount=0; /*菜单项数目为0/Mb->mtail->content=menutitle; /*把菜单的字符串指针指向menutitle*/Mb->mtail->next=NULL;Mb->mtail->sub=Mb->mtail->head=Mb->mtail->tail=NULL; /*把菜单项全部置NULL*/Mb->number+;/*菜单栏中number加1,表示加进去了一个菜单*/ 2. 菜单项构造函数/*该函数的功能是根据menu指定的字符串,往该菜单中添加以itemtitle为字符串的菜单项比如additem(“File”,”Open”)则执行向File菜单中添加一项itemtitle菜单项*/void additem(char *menu,char *itemtitle) Mb->mpoint=Mb->mhead; /*先把指针指向菜单头,这里借用Mb中的mpoint为了不用额外的变量*/ while(Mb->mpoint!=NULL) if(stricmp(Mb->mpoint->content,menu)=0) /*遍历menu链表,如果找到一项和menu指定字符串相等的,则记录下来,跳出,*/ break; Mb->mpoint=Mb->mpoint->next; if(Mb->mpoint->tail=NULL) /*如果tail为空,则说明没有构造头节点head*/ if(Mb->mpoint->head=(submenu *)malloc(sizeof(submenu)=NULL) doerror("System error"); Mb->mpoint->head->before=NULL; Mb->mpoint->sub=Mb->mpoint->tail=Mb->mpoint->head; else if(Mb->mpoint->tail->next=(submenu *)malloc(sizeof(submenu)=NULL) doerror("System error"); Mb->mpoint->tail->next->before=Mb->mpoint->tail; Mb->mpoint->tail=Mb->mpoint->tail->next; if(strlen(itemtitle)>Mb->mpoint->subwidth) Mb->mpoint->subwidth=strlen(itemtitle); /*该语句主要计算一下刚加进来的菜单项的字符数,如果比菜单的宽度还要大,则把该宽度赋值给subwidth,主要是为了画菜单是宽度足够*/ Mb->mpoint->subcount+;/*菜单项数目加一*/ Mb->mpoint->tail->number=Mb->mpoint->subcount; Mb->mpoint->tail->isactive=0; Mb->mpoint->tail->content=itemtitle; Mb->mpoint->tail->next=NULL; 3. 绘画菜单栏void drawmenu() Mb->mpoint=Mb->mhead; rectangle(0,0,getmaxx()-1,Mb->y+Mb->barheight);/*画一个方框*/ while(Mb->mpoint!=NULL)outtextxy(Mb->mpoint->number*Mb->baritemwidth+Mb->x+5,Mb->y+6,Mb->mpoint->content); /*在菜单栏中逐项画出菜单的内容*/Mb->mpoint=Mb->mpoint->next;4. 绘画当前激活的菜单void drawsubmenu()submenu *temp;int x; /*x记录当前画菜单的x位置*/x=Mb->mpoint->number*Mb->baritemwidth+Mb->x;temp=Mb->mpoint->head;copyimage(x,Mb->barheight+2,x+Mb->mpoint->subwidth*8+5,(Mb->mpoint->subcount+1)*Mb->barheight+3); /*保存绘画区的内容,copyimage为自写的函数*/setfillstyle(1,getbkcolor();bar(x,Mb->barheight+2,x+Mb->mpoint->subwidth*8+5,(Mb->mpoint->subcount+1)*Mb->barheight+3); /*用背景色把绘画区覆盖一下*/rectangle(x,Mb->barheight+2,x+Mb->mpoint->subwidth*8+5,(Mb->mpoint->subcount+1)*Mb->barheight+3); /*画一个方框*/while(temp!=NULL)if(temp->isactive) /*如果是当前激活的菜单,则画一个红色方框背景*/setfillstyle(1,RED);bar(x+2,temp->number*Mb->barheight+4,x+Mb->mpoint->subwidth*8+3,(temp->number+1)*Mb->barheight-1);outtextxy(x+5,temp->number*Mb->barheight+5,temp->content);temp=temp->next;4. 进入菜单/*根据menu指定的字符串,说明用户从哪项菜单进入菜单,如gotomenucur(”File”)说明用户激活了“File”菜单*/void gotomenucur(char *menu)Mb->mpoint=Mb->mhead;while(Mb->mpoint->next!=NULL)if(stricmp(Mb->mpoint->content,menu)=0)break;Mb->mpoint=Mb->mpoint->next;Mb->mpoint->sub=Mb->mpoint->head;Mb->mpoint->sub->isactive=1;drawsubmenu();5. 菜单按键处理void menukey()int key;while(1)key=get_key();switch(key)case KEY_LEFT: /*说明用户按下了向左按键,Mb->mpoint应该向前移一项*/Mb->mpoint->sub->isactive=0;backimage(Mb->mpoint->number*Mb->baritemwidth+Mb->x,Mb->barheight+2);if(Mb->mpoint->before!=NULL) /*如果当前已经是mhead了,应该指向mtail*/Mb->mpoint=Mb->mpoint->before;elseMb->mpoint=Mb->mtail;Mb->mpoint->sub=Mb->mpoint->head;Mb->mpoint->sub->isactive=1;drawsubmenu();/*重画菜单,跳出*/break;case KEY_RIGHT: /*说明用户按下了向右键,解释同KEY_LEFT*/Mb->mpoint->sub->isactive=0;backimage(Mb->mpoint->number*Mb->baritemwidth+Mb->x,Mb->barheight+2);if(Mb->mpoint->next!=NULL)Mb->mpoint=Mb->mpoint->next;elseMb->mpoint=Mb->mhead;Mb->mpoint->sub=Mb->mpoint->head;Mb->mpoint->sub->isactive=1;drawsubmenu();break;case KEY_UP: /*说明用户按下了向上键,应把当前激活的菜单项向上移一项*/Mb->mpoint->sub->isactive=0;backimage(Mb->mpoint->number*Mb->baritemwidth+Mb->x,Mb->barheight+2);if(Mb->mpoint->sub->before!=NULL)Mb->mpoint->sub=Mb->mpoint->sub->before;elseMb->mpoint->sub=Mb->mpoint->tail;Mb->mpoint->sub->isactive=1;drawsubmenu();break;case KEY_DOWN: /*说明用户按下了向下键,当前菜单项应向下移一项*/Mb->mpoint->sub->isactive=0;backimage(Mb->mpoint->number*Mb->baritemwidth+Mb->x,Mb->barheight+2);if(Mb->mpoint->sub->next!=NULL)Mb->mpoint->sub=Mb->mpoint->sub->next;elseMb->mpoint->sub=Mb->mpoint->head;Mb->mpoint->sub->isactive=1;drawsubmenu();break;case ENTER: /*说明用户按下了回车键,调用Mb->docommand()*/Mb->mpoint->sub->isactive=0;backimage(Mb->mpoint->number*Mb->baritemwidth+Mb->x,Mb->barheight+2);Mb->docommand();return;case ESC: /*说明用户按下了退出键,把拷贝的屏幕区域放回,不作任何处理*/Mb->mpoint->sub->isactive=0;backimage(Mb->mpoint->number*Mb->baritemwidth+Mb->x,Mb->barheight+2);return;游标与滚屏l 思想在屏幕上显示的是两个队列,一个是等待队列,一个是就绪队列。设置了一个游标,可以用上下键移动指向每个进程,然后对指向进程进行各种操作,包括挂起,解挂,删除。我设置的屏幕上最多只能显示12个进程,就绪最多6个,等待最多6个,那么当进程多于此数时,在用户按上下键时,应该有滚屏功能。滚屏的思想如下:假设有就绪队列里有N1个进程,每个进程编号1,2,3.N1-1,N1。等待队列中有N2个进程,每个进程编号1,2,3N2-1,N2。假设当前游标指向的进程编号小于6,则绘画1到6个进程(如果进程数小于6则画出所有进程),如果当前游标指向的进程编号为N(N>6),则绘画N6到N个,这样就实现了滚屏。当当前游标位置位于就绪队列结尾,则当用户按下向下按键时,应该将游标移动到等待队列的第一个;当当前游标位置位于就绪队列第一个,则当用户按下向上按键时,应该移动到等待队列最后一个;同理,当当前游标位于等待队列队尾对首时,应移动就绪队列队首队尾。l 函数实现因为我把等待队列和就绪队列放在同一个链表里,所以要实现上面的功能可能有点problem,但多用几个函数就能实现。1. /*这个函数用来给每个进程编号*/void updateprocess()int i=1,j=1;process *temp;temp=phead;while(temp)if(temp->isrun) /*给就绪队列中的进程编号*/temp->pos=i+;else /*给等待队列中的进程编号*/temp->pos=j+;temp=temp->next;2. /*这个函数用来得到列表中就绪队列中的第一个*/process *getfirstrun() process *temp; if(!phead) return NULL; temp=phead; while(temp!=NULL) if(temp->isrun) /*找到第一个,就跳出循环*/ break; temp=temp->next; return temp->isrun?temp:NULL; /*如果找到就返回,否则就返回NULL,因为可能存在唯一一个等待队列中的*/ 3. /*该函数用来获取列表中就绪队列中的最后一个*/ process *gettailrun() process *temp; if(!ptail) /*如果列表为空,则返回NULL*/ return NULL; temp=ptail; /*从列表尾部开始找*/ while(temp!=NULL) if(temp->isrun) /*如果找到,就跳出循环*/ break; temp=temp->before; return temp->isrun?temp:NULL; /*判断找到的是不是就绪队列中的如果不是就返回NULL,因为可能存在只有一个等待队列中的*/ 4. /*这个函数用来找相对于p的下一个就绪队列中的进程*/ process *getnextrun(process *p) process *temp; if(!p) return NULL; temp=p->next; while(temp!=NULL) if(temp->isrun) /*如果找到,就跳出循环*/ break; temp=temp->next; return temp; 5. /*这个函数用来找相对于p的前一个就绪队列中的进程*/ process *getbeforerun(process *p) process *temp; if(!p) return NULL; temp=p->before; while(temp!=NULL) if(temp->isrun) break; temp=temp->before; return temp; 6. /*这个函数用来找等待队列中的第一个,一下三个函数原理跟就绪队列中的操作函数一样,只是把查找的条件改成!temp->isrun*/ process *getfirstready() process *temp; if(!phead) return NULL; temp=phead; while(temp!=NULL) if(!temp->isrun) break; temp=temp->next; return temp->isrun?NULL:temp; 7. process *gettailready() process *temp; if(!ptail) return NULL; temp=ptail; while(temp!=NULL) if(!temp->isrun) break; temp=temp->before; return temp->isrun?NULL:temp; 8. process *getnextready(process *p) process *temp; if(!p) return NULL; temp=p->next; while(temp!=NULL) if(!temp->isrun) break; temp=temp->next; return temp; 9. process *getbeforeready(process *p) process *temp; if(!p) return NULL; temp=p->before; while(temp!=NULL) if(!temp->isrun) break; temp=temp->before; return temp; 10. /*这个函数用来得到下一个游标的位置*/void getnext() process *temp; if(phead=ptail)/*如果链表中只有一个进程,则什么也不处理,返回*/ ppoint=phead; return; if(ppoint=gettailrun()/*如果当前游标位置是就绪队列中的最后一个*/ temp=getfirstready();/*则指向第一个等待队列*/ ppoint=temp?temp:getfirstrun(); else if(ppoint=gettailready()/*如果当前游标位置是等待队列中的最后一个*/ temp=getfirstrun();/*则指向就绪队列中的第一个*/ ppoint=temp?temp:getfirstready(); else if(ppoint->isrun) /*如果当前队列在就绪队列中移动*/ ppoint=getnextrun(ppoint); /*移向就绪队列中的下一个*/ else ppoint=getnextready(ppoint); /*移向等待队列中的下一个*/ 11. /*这个函数用来得到上一个游标的位置,基本的解释同getnext()差不多*/ void getbefore() process *temp;if(phead=ptail) ppoint=phead;return; if(ppoint=getfirstrun() temp=gettailready(); ppoint=temp?temp:gettailrun(); else if(ppoint=getfirstready() temp=gettailrun(); ppoint=temp?temp:gettailready(); else if(ppoint->isrun) ppoint=getbeforerun(ppoint); else ppoint=getbeforeready(ppoint); 12. /*按键处理函数*/void key_U_D(int key)switch(key)case KEY_DOWN:if(!phead) ppoint=NULL;else getnext();break;/*如果按下的是向下键*/case KEY_UP:if(!ptail) ppoint=NULL;else getbefore();break; /*如果按下的是向上键*/if(ppoint) /*drawl_r(int,int)这个函数根据传递进来的两个参数指明应该画的起始编号*/if(ppoint->pos>6)if(ppoint->isrun)drawl_r(ppoint->pos-6,0);else drawl_r(0,ppoint->pos-6);else drawl_r(0,0);else drawl_r(0,0);获取用户按键C语言库函数提供的getch(),或bioskey()在处理字符和菜单输入时有点麻烦,改写了一个函数int get_key() union REGS rg; rg.h.ah=0; int86(0x16,&rg,&rg); if(rg.h.al=0)/*说明按下了修饰键,把这个值左移8位*/return rg.h.ah<<8; return rg.h.al; /*直接返回按下的键值,实际上是ASCII*/举例:当用户按下ALTF时,返回的是8448,而按下F时,返回的是F的ASCII图形屏幕下获取用户的输入因为这次课程设计只需获得用户输入的整数,所以处理也比较简单。long getinput(char *mess)/*输入框提示的信息*/char desc50,number10,*endptr,*image;int i=0,key,width,x=200,y=300,size,color;width=strlen(mess)+10; /*计算窗口的宽度,按字符数来算,其中输入的数字长度最大为10*/size=imagesize(x,y,x+width*6,y+50); /*把窗口内的屏幕保存下来*/if(image=(char *)malloc(size)=NULL)doerror("System error");getimage(x,y,x+width*6,y+50,image);setfillstyle(1,getbkcolor();bar(x,y,x+width*6,y+50);rectangle(x,y,x+width*6,y+50); /*用背景色覆盖一下,相当于清屏*/strcpy(desc,mess);outtextxy(x+10,y+20,mess);while(key=get_key()!=ENTER) /*如果没有按下回车,则不退出*/if(key=ESC) /*如果按下ESC,则把拷贝的屏幕放回去,返回1*/putimage(x,y,image,0);free(image);return -1;if(key>=48&&key<=57|key=8) /*如果按下的是数字键或者是退格键*/if(key=8) /*如果是退格键,就用背景色把原来的字符画一遍,相当于覆盖,然后去掉结尾一个,用前景色画字符,就相当于删掉一个字符(实际上也删掉了)*/color=getcolor();setcolor(getbkcolor();outtextxy(x+10,y+20,strcat(desc,number);setcolor(color);number-i='0' /*这句相当于删掉一个字符*/else if(i<10)numberi+=key; /*把字符附加到末尾*/numberi='0'descstrlen(mess)='0'outtextxy(x+10,y+20,strcat(desc,number);putimage(x,y,image,0);free(image);return strtol(number,&endptr,10); /*把输入的字符转换为数字返回*/程序执行流程首先说明一下handle()函数的功能:void handler()int time,i,j,pos;/*time用来记录上次执行handle到这次执行handle的时间间隔,i,j用来控制循环,pos用来记录光标(用来指向每个进程的一个小方块)的位置*/if(ppoint!=NULL)if(ppoint->pos>6) /*因为每个队列最多只能显示6个队列,所以当当前光标指向的进程的pos>6时,pos一定是底部pos=6;else pos=ppoint->pos;bar(1-ppoint->isrun)*450,(pos-1)*50+80,(1-ppoint->isrun)*450+15,(pos-1)*50+85);/*画一个游标if(stop) /*stop是全局变量(为这是一个模拟程序,所以当用户想暂停或者什么的,可以暂停)果stop是true,则什么事都不做return;i=getnum(1); /*获取就绪队列中的进程总数*/j=getnum(0); /*获取等待队列中的进程总数*/if(i+j)<=0) /*如果两个队列为空*/stop=1;fresh();/*刷新一下屏幕*/return;if(i<maxrun&&j>0&&canrun) /*如果就绪队列中的进程数小于maxrun(maxrun为就绪队列中的最大数目)且等待队列不为空,且有足够的内存(maxrun为true时表示有足够内存)*/getfromeready();/*从等待队列中选取一个优先级最高,时间最少的*/coverfront();/*把游标重画一遍(这里放这个函数好像有点多余)*/gettime(&t2);time=(t2.ti_hour-t1.ti_hour)*60*60*100+(t2.ti_min-t1.ti_min)*60*100+(t2.ti_sec-t1.ti_sec)*100+t2.ti_hund-t1.ti_hund; /*计算两次执行handle的时间差,其实可以用gettime()这个库函数,但当时没发现。*/runtime-=time; /*runtime是时间片大小,是个全局变量*/drawsector();/*画屏幕中间的时间片转盘*/if(runtime<=0) /*如果当前时间片用完了*/updatepri();/*更新一下进程优先权,防止饿死*/drawl_r(0,0); /*重画进程列表*/Find_H_P();/*从就绪队列中找优先级最高的,时间最少的*/runtime=roundtime; /*roundtime是用来供用户设定时间片大小的,把runtime的大小设为roundtime*/else drawcur(time); /*画运行进程,这实际是个动画。*/t1=t2; /*更新t1的值,作为下次时间计算的标准*/setfillstyle(1,RED); /*重新设定填充模式,因为drawcru(time)函数中可能改变了填充模式*/Handle函数流程图:判断stop等队列中的进程总数小于maxrun且等待队列中有进程且有足够内存,从等待队列中选取一个优先级最高,时间最少的进程进就绪队列从运行队列中减去所运行了的时间,并用进度条在屏幕上显示出来False是否因为程序中用到了菜单,所以程序要保证执行handle(),同时又不能耽误用户的输入对菜单的操作,有两种方法。方法一:利用DOS的时钟中断 int 21H  AH=0x1C  每秒产生18.2次中断。在main函数中添加oldhandler = getvect(INTR);setvect(INTR, handler);其中INTR为宏定义define INTR 0x1c程序的流程图:等待用户按键捕获按键,进行相应处理处理结束产生时钟中断,调用handle函数产生中断方法二:用kbhit()检测是否有有按键按下,如果有,则调用相应的按键处理函数,如果没有则执行handle函数,然后调用delay函数延迟下一个循环。程序流程图:是否有键盘按下捕获按键进行相应处理处理结束执行handle函数本次循环延世没有有算法描述:进程调度算法:如果stop为false,说明用户开始程序模拟,检查等待队列中的进程总数是否为maxrun(为系统运行的负载),如果小于,则检查等待队列中是否有进程,如果有,则再检查是否有足够内存,如果都满足,则从等待队列中选取优先级最高,时间最少的进程运行。当一个时间片运行完时,则加大就绪队列中相对低优先级的优先级数,然后再选取下一个优先级最高,时间最少的运行。这样可以防止低优先级进程的饿死。内存分配算法:在选进程进入就绪队列前,先看看当前内存分配算法是最佳适应还是最先适应,看内存中是否存在一块足够的内存,如果足够,则从内存中划去这一块,如果这一块相同大,则要删除该链表节点。内存回收算法:当一个进程运行结束时,要回收内存,先记录下该内存块的起始和终止地址

    注意事项

    本文(中南大学 操作系统实验报告课程设计报告.doc)为本站会员(文库蛋蛋多)主动上传,三一办公仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一办公(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    备案号:宁ICP备20000045号-2

    经营许可证:宁B2-20210002

    宁公网安备 64010402000987号

    三一办公
    收起
    展开