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

上传人:仙*** 文档编号:30235322 上传时间:2021-10-09 格式:DOC 页数:48 大小:522.50KB
收藏 版权申诉 举报 下载
中南大学 操作系统实验报告课程设计报告_第1页
第1页 / 共48页
中南大学 操作系统实验报告课程设计报告_第2页
第2页 / 共48页
中南大学 操作系统实验报告课程设计报告_第3页
第3页 / 共48页
资源描述:

《中南大学 操作系统实验报告课程设计报告》由会员分享,可在线阅读,更多相关《中南大学 操作系统实验报告课程设计报告(48页珍藏版)》请在装配图网上搜索。

1、操作系统实验报告 界面设计 l 菜单 菜单包括菜单栏,菜单,菜单项,一个菜单栏可以包括N个菜单,一个菜单可以包括菜单项。C语言设计菜单的思想是用双向链表,先保存绘图区的内容,再在上面画菜单。 l 菜单结构图 菜单栏 菜单1 菜单2 菜单n …….…. 尾指针 头指针 当前指向菜单 菜单项1 菜单项2 。 。 。 。 菜单项n 头指针 其他菜单项结构类似 结尾指针 l 数据结构 1. 菜单栏: typedef struct menubar_s{ int number,x,y,barheight,baritemwidth;/*numbe

2、r用来记录菜单项的数目,x,y用来记录菜单栏在屏幕上的位置,barheight用来控制菜单栏的高度,baritemwidth用来控制每项菜单的宽度*/ struct menu_s *mhead; /*指向第一个菜单*/ struct menu_s *mtail; /*指向最后一个菜单*/ struct menu_s *mpoint; /*当用户按下左右箭头时用来记录指向那个菜单,初始指向mhead*/ void (* docommand)(); /*菜单时间的处理函数*/ }MenuBar; 2. 菜单: typedef struct menu_s{ int numb

3、er; /*菜单是菜单栏中的第几项*/ 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_

4、s *tail; /*指向最后一个菜单项*/ }Menu; 3. 菜单项: typedef struct submenu_s{ int number; /*菜单项是菜单中的第几项*/ int isactive; /*是否激活*/ char *content; /*显示的字符串*/ struct submenu_s *next; /*指向下一个菜单项*/ struct submenu_s *before; /*指向前一个菜单项*/ }submenu; l 函数实现 1. 菜单构造函数 /*该函数的功能主要是根据指定的menutitle字符串,往菜单栏中添加一项菜

5、单*/ 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->ba

6、rheight=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->

7、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->mta

8、il->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(“Fil

9、e”,”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-

10、>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

11、=(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); /*该语句主要计算一下刚加进来的菜单项的字符数,如果比菜单的宽度还

12、要大,则把该宽度赋值给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

13、,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=M

14、b->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

15、+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->s

16、ubwidth*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!

17、=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: /*说明用户按下了向

18、左按键,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; else Mb->mpoint=Mb->mtail; Mb->mpoint->sub=Mb->mpoin

19、t->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->mpoin

20、t->next; else Mb->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->barhe

21、ight+2); if(Mb->mpoint->sub->before!=NULL) Mb->mpoint->sub=Mb->mpoint->sub->before; else Mb->mpoint->sub=Mb->mpoint->tail; Mb->mpoint->sub->isactive=1; drawsubmenu(); break; case KEY_DOWN: /*说明用户按下了向下键,当前菜单项应向下移一项*/ Mb->mpoint->sub->isactive=0; back

22、image(Mb->mpoint->number*Mb->baritemwidth+Mb->x,Mb->barheight+2); if(Mb->mpoint->sub->next!=NULL) Mb->mpoint->sub=Mb->mpoint->sub->next; else Mb->mpoint->sub=Mb->mpoint->head; Mb->mpoint->sub->isactive=1; drawsubmenu(); break; case ENTER: /*说明用户按下了回车键,调用Mb->d

23、ocommand()*/ 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; } } }

24、 游标与滚屏 l 思想 在屏幕上显示的是两个队列,一个是等待队列,一个是就绪队列。设置了一个游标,可以用上下键移动指向每个进程,然后对指向进程进行各种操作,包括挂起,解挂,删除。我设置的屏幕上最多只能显示12个进程,就绪最多6个,等待最多6个,那么当进程多于此数时,在用户按上下键时,应该有滚屏功能。滚屏的思想如下:假设有就绪队列里有N1个进程,每个进程编号1,2,3…….N1-1,N1。等待队列中有N2个进程,每个进程编号1,2,3……N2-1,N2。假设当前游标指向的进程编号小于6,则绘画1到6个进程(如果进程数小于6则画出所有进程),如果当前游标指向的进程编号为N(N>6),则绘画

25、N-6到N个,这样就实现了滚屏。当当前游标位置位于就绪队列结尾,则当用户按下向下按键时,应该将游标移动到等待队列的第一个;当当前游标位置位于就绪队列第一个,则当用户按下向上按键时,应该移动到等待队列最后一个;同理,当当前游标位于等待队列队尾对首时,应移动就绪队列队首队尾。 l 函数实现 因为我把等待队列和就绪队列放在同一个链表里,所以要实现上面的功能可能有点problem,但多用几个函数就能实现。 1. /*这个函数用来给每个进程编号*/ void updateprocess(){ int i=1,j=1; process *temp; temp=phead; whil

26、e(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)

27、{ /*找到第一个,就跳出循环*/ break; } temp=temp->next; } return temp->isrun?temp:NULL; /*如果找到就返回,否则就返回NULL,因为可能存在唯一一个等待队列中的*/ } 3. /*该函数用来获取列表中就绪队列中的最后一个*/ process *gettailrun(){ process *temp; if(!ptail) /*如果列表为空,则返回NULL*/ return NULL; temp=ptail; /*从列表尾部开始找*/ while(t

28、emp!=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-

29、>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)

30、 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->ne

31、xt; } 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

32、*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){ i

33、f(!temp->isrun) break; temp=temp->before; } return temp; } 10. /*这个函数用来得到下一个游标的位置*/ void getnext(){ process *temp; if(phead==ptail){/*如果链表中只有一个进程,则什么也不处理,返回*/ ppoint=phead; return; } if(ppoint==gettailrun()){/*如果当前游标位置是就绪队列中的最后一个*/ temp=getfirstready();/*则指

34、向第一个等待队列*/ ppoint=temp?temp:getfirstrun(); }else if(ppoint==gettailready()){/*如果当前游标位置是等待队列中的最后一个*/ temp=getfirstrun();/*则指向就绪队列中的第一个*/ ppoint=temp?temp:getfirstready(); }else if(ppoint->isrun){ /*如果当前队列在就绪队列中移动*/ ppoint=getnextrun(ppoint); /*移向就绪队列中的下一个*/ }else { ppoint

35、=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==g

36、etfirstready()){ 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

37、();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 dra

38、wl_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*/ } 举例: 当用户按下ALT+F时,

39、返回的是8448,而按下F时,返回的是F的ASCII 图形屏幕下获取用户的输入 因为这次课程设计只需获得用户输入的整数,所以处理也比较简单。 long getinput(char *mess){/*输入框提示的信息*/ char desc[50],number[10],*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);

40、 /*把窗口内的屏幕保存下来*/ 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=ge

41、t_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=getcol

42、or(); setcolor(getbkcolor()); outtextxy(x+10,y+20,strcat(desc,number)); setcolor(color); number[--i]=\0; /*这句相当于删掉一个字符*/ }else if(i<10){ number[i++]=key; /*把字符附加到末尾*/ number[i]=\0; } desc[strlen(mess)]=\0; outtextxy(x+10,y+20,strcat(desc,number)); }

43、 } 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){ /*因为每个队列最多只能显示

44、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=getnu

45、m(0); /*获取等待队列中的进程总数*/ if((i+j)<=0){ /*如果两个队列为空*/ stop=1; fresh();/*刷新一下屏幕*/ return; } if(i0&&canrun){ /*如果就绪队列中的进程数小于maxrun(maxrun为就绪队列中的最大数目)且等待队列不为空,且有足够的内存(maxrun为true时表示有足够内存)*/ getfromeready();/*从等待队列中选取一个优先级最高,时间最少的*/ coverfront();/*把游标重画一遍(这里放这个函数好像有点多余)*/ }

46、 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){ /*如果当前时间片用完了*/ update

47、pri();/*更新一下进程优先权,防止饿死*/ drawl_r(0,0); /*重画进程列表*/ Find_H_P();/*从就绪队列中找优先级最高的,时间最少的*/ runtime=roundtime; /*roundtime是用来供用户设定时间片大小的,把runtime的大小设为roundtime*/ }else { drawcur(time); /*画运行进程,这实际是个动画。*/ } t1=t2; /*更新t1的值,作为下次时间计算的标准*/ setfillstyle(1,RED); /*重新设定填充模式,因为drawcru(time)函数中可

48、能改变了填充模式*/ } Handle函数流程图: 判断stop 等队列中的进程总数小于maxrun且等待队列中有进程且有足够内存, 从等待队列中选取一个优先级最高,时间最少的进程进就绪队列 从运行队列中减去所运行了的时间,并用进度条在屏幕上显示出来 False 是 否 因为程序中用到了菜单,所以程序要保证执行handle(),同时又不能耽误用户的输入对菜单的操作,有两种方法。 方法一:利用DOS的时钟中断 int 21HAH=0x1C每秒产生18.2次中断。在main函数中添加 oldhandler = getvect(INTR); setvect(INTR

49、, handler); 其中INTR为宏定义#define INTR 0x1c 程序的流程图: 等待用户按键 捕获按键,进行相应处理 处理结束 产生时钟中断,调用handle函数 产生中断 方法二:用kbhit()检测是否有有按键按下,如果有,则调用相应的按键处理函数,如果没有则执行handle函数,然后调用delay函数延迟下一个循环。 程序流程图: 是否有键盘按下 捕获按键进行相应处理 处理结束 执行handle函数 本次循环延世 没有 有 算法描述: 进程调度算法:如果stop为false,说明用户开始程序模拟,检查等待队列中的进程总数是否为m

50、axrun(为系统运行的负载),如果小于,则检查等待队列中是否有进程,如果有,则再检查是否有足够内存,如果都满足,则从等待队列中选取优先级最高,时间最少的进程运行。 当一个时间片运行完时,则加大就绪队列中相对低优先级的优先级数,然后再选取下一个优先级最高,时间最少的运行。这样可以防止低优先级进程的饿死。 内存分配算法:在选进程进入就绪队列前,先看看当前内存分配算法是最佳适应还是最先适应,看内存中是否存在一块足够的内存,如果足够,则从内存中划去这一块,如果这一块相同大,则要删除该链表节点。 内存回收算法:当一个进程运行结束时,要回收内存,先记录下该内存块的起始和终止地址,遍历内存链表,看该

51、块内存的相邻两块是不是也是空闲的,这时候可能会出现三种情况: 情况一:相邻两块只有一块是空闲的,则直接合并进去; 情况二:相邻两块都是空闲的,则要把这三块合并成一块,并删除一个节点; 情况三:相邻两块都不空闲,则直接创建一个内存节点,放入队尾。 最佳适应算法:遍历空闲内存块链表,找出大于所需内存大小且是最小的一块。 最先适应算法:从两表头开始,只要找到一块大于所需大小的就停止。 PCB数据结构 typedef struct process_t{ int pid;/*进程的pid*/ int isrun; /*进程是否在就绪队列中,因为所有状态的进程都在一个队列中,所以必须

52、有这些标识符变量来识别,实际操作系统中不是这样的*/ int ishalt; /*进程是否被挂起*/ int pos; /*进程在屏幕中的位置,从1开始按等待和就绪递增*/ int priority; /*进程的优先级*/ int time_total; /*所需时间总数*/ int time_left; /*还剩下的时间*/ long startaddr; /*内存的起始地址*/ long size; /*内存的大小*/ void (*fun)(); /*函数入口*/ struct process_t *next; /*指向下一个pcb*/ struc

53、t process_t *before; /*指向上一个pcb*/ }process; 内存空闲块数据结构 typedef struct memory_t{ long startaddr;/*内存的起始地址*/ long size;/*空闲内存的大小*/ struct memory_t *next; /*指向下一个空闲内存块*/ struct memory_t *before; /*指向上一个空闲内存块*/ }memory; 屏幕画图 菜单画法: 先计算当前所画菜单的大小,在内存开辟一个区域保存所画区域内容,然后从菜单头节点开始画一直画到链表末尾,如果用户取消了或

54、者按下了回车只要把保存的内容放回原来的地方。 进程在屏幕上的画法: 由于链表只有一个,而有就绪,等待,运行三个队列,其实运行中只有一个进程,只要在用一个process指针指向当前运行进程就可以了。那么怎么把同一个链表中的进程分别画在屏幕两边的就绪和等待队列中呢?(1-process->isrun)*screenweidth,这样,如果它是就绪队列中的(它的isrun是1),它就在屏幕的左边,如果它是等待队列中的(它的isrun是0),它就在屏幕的右边。 关于集成图形驱动做成exe文件 在tc里头,生成的exe文件如果是文本模式的,则可以运行,而如果是图形模式的,生成的exe老是提示你没

55、有初始化图形驱动,可以把图形驱动集成到graphic里头,方法如下: 注册图形驱动: bgiobj EGAVGA 回车 得到EGAVGA.OBJ TLIB LIB\GRAPHICS.LIB+EGAVGA.OBJ回车即可 在程序中用registerbgidriver(EGAVGA_driver); 其它对应的如下 CAG.BGI CGA_driver EGA.VGA.BGI EGAVGA_driver HERC.BGI HERC_driver ATT.BGI ATT_driver PC3270.BGI PC3270_driver IBM8514.BGI IBM

56、8514_driver 注册字体: bgiobj trip|litt|sans|goth分别对应字体trip.chr|litt.chr|sans.chr|goth.chr tlib lib\graphics.lib+litt.obj 字型驱动 registerbgifont() litt.chr tlib得到的字符名入"samll_font" 源程序: #include #include #include #include #include #include

57、h.h> #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/*定义按下alt+f返回的整数值*/ #define ALT_S 79

58、36/*定义按下alt+s返回的整数值*/ #define ALT_O 6144/*定义alt+o返回的整数值*/ #define ALT_H 8960/*定义alt+h返回的整数值*/ #define ESC 27/*定义esc返回的整数值,以上这些键值都是有get_key()函数获得*/ typedef struct menubar_s{ int number,x,y,barheight,baritemwidth; struct menu_s *mhead; struct menu_s *mtail; struct menu_s *mpoint; void (*

59、 docommand)(); }MenuBar; /*定义一个菜单栏数据结构,在上面已经解释过*/ typedef struct menu_s{ int 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; /*定义一个菜单结构体,具体在上面已经解释过*/ typ

60、edef struct submenu_s{ int number; int isactive; char *content; struct submenu_s *next; struct submenu_s *before; }submenu; /*定义一个菜单项,具体已在上面解释过*/ typedef struct process_t{ int pid; int isrun; int ishalt; int pos; int priority; int time_total; int time_left; long startaddr

61、; long size; void (*fun)(); struct process_t *next; struct process_t *before; }process; /*定义一个pcb,在上面已经解释过*/ typedef struct memory_t{ long startaddr; long size; struct memory_t *next; struct memory_t *before; }memory; /*定义一个空闲内存块结构,在上面已经解释过*/ void docommand(); void drawprocess(p

62、rocess *,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 c

63、reatememory(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函数

64、执行之间的时间差*/ 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()

65、 { union REGS rg; rg.h.ah=0; int86(0x16,&rg,&rg); if(rg.h.al==0){ return rg.h.ah<<8; } return rg.h.al; }/*这个函数用来获取按键值,在上面已经解释过*/ void doerror(char *s){ int color; setfillstyle(1,getbkcolor()); bar(200,200,300,300); rectangle(300,300,400,400); outtextxy(320,340,s); g

66、etch(); closegraph(); exit(1); }/*如果系统内存不足或者文件打不开,给出提示信息,并结束程序(目前也只能这样做)*/ void addmenu(char *menutitle){ /*添加一个菜单*/ if(Mb==NULL){ /*如果Mb为NULL,说明菜单栏还没有初始化,接下去执行一些初始化工作*/ if((Mb=(MenuBar *)malloc(sizeof(MenuBar)))==NULL) doerror("System error");/*分配一块内存区域*/ Mb->number=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){ /*如果当

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

相关资源

更多
正为您匹配相似的精品文档
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

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

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


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