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

上传人:仙*** 文档编号:30235322 上传时间:2021-10-09 格式:DOC 页数:48 大小:522.50KB
返回 下载 相关 举报
中南大学 操作系统实验报告课程设计报告_第1页
第1页 / 共48页
中南大学 操作系统实验报告课程设计报告_第2页
第2页 / 共48页
中南大学 操作系统实验报告课程设计报告_第3页
第3页 / 共48页
点击查看更多>>
资源描述
操作系统实验报告界面设计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(N6),则绘画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-pos6)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=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(ipos6) /*因为每个队列最多只能显示6个队列,所以当当前光标指向的进程的pos6时,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(i0&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(runtimeisrun)*screenweidth,这样,如果它是就绪队列中的(它的isrun是1),它就在屏幕的左边,如果它是等待队列中的(它的isrun是0),它就在屏幕的右边。关于集成图形驱动做成exe文件在tc里头,生成的exe文件如果是文本模式的,则可以运行,而如果是图形模式的,生成的exe老是提示你没有初始化图形驱动,可以把图形驱动集成到graphic里头,方法如下:注册图形驱动:bgiobj EGAVGA 回车得到EGAVGA.OBJTLIB LIBGRAPHICS.LIB+EGAVGA.OBJ回车即可在程序中用registerbgidriver(EGAVGA_driver);其它对应的如下CAG.BGI CGA_driverEGA.VGA.BGI EGAVGA_driverHERC.BGIHERC_driverATT.BGIATT_driverPC3270.BGIPC3270_driverIBM8514.BGIIBM8514_driver注册字体:bgiobj trip|litt|sans|goth分别对应字体trip.chr|litt.chr|sans.chr|goth.chrtlib libgraphics.lib+litt.obj字型驱动registerbgifont()litt.chrtlib得到的字符名入samll_font源程序:#include #include #include #include #include #include #include /*包含一些必要的头文件*/#define INTR 0X1C/*定义时钟中断号*/#define ENTER 13/*定义回车键*/#define KEY_UP 18432/*定义向上键的整数值*/#define KEY_DOWN 20480/*定义向下键的整数值*/#define KEY_LEFT 19200/*定义向左键的整数值*/#define KEY_RIGHT 19712/*定义向右键的整数值*/#define ALT_F 8448/*定义按下altf返回的整数值*/#define ALT_S 7936/*定义按下alts返回的整数值*/#define ALT_O 6144/*定义alto返回的整数值*/#define ALT_H 8960/*定义alth返回的整数值*/#define ESC 27/*定义esc返回的整数值,以上这些键值都是有get_key()函数获得*/typedef struct menubar_sint number,x,y,barheight,baritemwidth;struct menu_s *mhead;struct menu_s *mtail;struct menu_s *mpoint;void (* docommand)();MenuBar; /*定义一个菜单栏数据结构,在上面已经解释过*/typedef struct menu_sint number;int subwidth;int subcount;char *content;struct menu_s *next;struct menu_s *before;struct submenu_s *sub;struct submenu_s *head;struct submenu_s *tail;Menu; /*定义一个菜单结构体,具体在上面已经解释过*/typedef struct submenu_sint number;int isactive;char *content;struct submenu_s *next;struct submenu_s *before;submenu; /*定义一个菜单项,具体已在上面解释过*/typedef struct process_tint pid;int isrun;int ishalt;int pos;int priority;int time_total;int time_left;long startaddr;long size;void (*fun)();struct process_t *next;struct process_t *before;process; /*定义一个pcb,在上面已经解释过*/typedef struct memory_tlong startaddr;long size;struct memory_t *next;struct memory_t *before;memory; /*定义一个空闲内存块结构,在上面已经解释过*/void docommand();void drawprocess(process *,int,int,int,int);void readfile();void writefile();void drawl_r(int,int);void addprocess();long getinput(char *);void savefile();void fresh();int findm_f_f(process *p);int findm_b_f(process *p);long getfreesize();void acceptm_f_f(process *p);void drawmembar();void creatememory(long,long);void rancreatep(long num);void randomcreate();void setmemsize();/*一些函数声明,一下开始定义全局变量*/MenuBar *Mb; /*一个菜单栏*/void *buff; /*用来保存画菜单时预先保存的区域*/process *phead,*ptail,*prunning,*ppoint; /*用来保存进程队列的头,尾,正在运行,和当前游标指向的一个进程*/struct time t1,t2; /*定义两个time结构体类型,用来记录在两次handle函数执行之间的时间差*/memory *mhead,*mtail; /*空闲内存块的头尾指针*/int roundtime=500,runtime=500,maxrun=5,stop=1,canrun=1,memway=1; /*roundtime用来保存时间片大小,runtime用来保存当前时间片大小,maxrun用来保存系统所能运行的最大进程数,stop用来控制是否停止模拟,canrun用来记录系统是否有足够内存,memway用来记录当前内存的适应方式(最佳适应还是最先适应)*/long memorysize=35460L; /*用来定义内存大小*/int get_key() union REGS rg; rg.h.ah=0; int86(0x16,&rg,&rg); if(rg.h.al=0)return rg.h.ahnumber=0;Mb-mpoint=Mb-mhead=Mb-mtail=NULL;Mb-x=0;Mb-y=0;Mb-barheight=18;Mb-baritemwidth=100;Mb-docommand=docommand; /*初始化Mb中的一些变量,具体的变量含义已在上面解释过*/if(Mb-mtail=NULL) /*如果当
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!