您好,欢迎访问三七文档
当前位置:首页 > 临时分类 > 基于线程的多任务调度系统的设计与实现实验报告
基于线程的多任务调度系统的设计与实现实验报告姓名陈振辉学号12224506班级5班1实验要求(1)线程的创建、撤消和CPU切换。掌握线程的定义和特征,线程的基本状态,线程的私有堆栈,线程控制块TCB,理解线程与进程的区别,实现线程的创建、撤消和CPU切换。(2)时间片轮转调度理解各种调度算法、调度的原因,完成时钟中断的截取,具体实现调度程序。(3)最高优先权优先调度理解优先权的概念,并实现最高优先权优先调度策略。(4)利用记录型信号量实现线程的同步理解同步的相关概念,掌握记录型信号量的概念及应用,并用记录型信号量实现生产者和消费者问题。(5)消息缓冲队列通信机制理解进程(线程)通信的基本概念,并用消息缓冲队列实现线程间的通信。功能设计1线程的创建和撤销线程的创建过程关键就是对私有堆栈和TCB初始化的过程,其过程如下:i,为新线程分配一空闲的线程控制块ii,为新线程的私有堆栈分配内存空间(因为对等线程共享程序段和数据段空间,所以创建线程时不必像创建进程那样再为程序段和数据段分配内存空间)iii,初始化新线程的私有堆栈,即按CPU调度时现场信息的保存格式布置堆栈。初始化线程控制块,即填入线程的外部标识符,设置好线程私有堆栈的始址,段址和栈顶指针,将线程的状态置为就绪状态2线程的调度引起CPU调度原因主要是有三种情况:时间片到时,线程执行完毕或正在执行的线程因等待某种事件而不能继续执行。由这些原因,调度程序可以通过两个函数分别处理不同原因引起的调度:New_int8()函数主要是处理因时间片到时引起的调度该调度可以通过截取时钟中断(int08)来完成;Swtch()函数主要是处理因其他原因引起的调度;New_int8()函数因为是通过截取时钟中断来实现,可以知道其是属于系统调度,由于涉及到系统调度的函数都是需要对DOS状态进行判断,以防止出现系统数据混乱等情况的发生(从Dos的不可重入性来得出),而Swtch()函数是处理因其他原因引起的调度,所以它所涉及到的仅仅是用户级的函数调度,没有涉及到系统级的函数调度,因此Swtch()函数不需要对Dos状态进行判断。3线程的阻塞与唤醒线程的阻塞:主要是当某一线程需要阻塞的时候,将其插入阻塞队列中,等待唤醒进程唤醒,所以其过程为:首先,将线程的状态置为阻塞态,然后将线程插入指定的阻塞队列末尾,并重新进行CPU调度。线程的唤醒:主要是唤醒阻塞队列里面的线程,所以其过程是:把阻塞队列头上的第一个线程的TCB取下来,并将其状态改为就绪状态,等待CPU调度4线程的同步与互斥在这个系统中是采用记录型信号量机制来实现同步与互斥的,实现的方法:采用P,V操作,设置两个信号量:一个为互斥信号量,一个为临界资源数目;5利用消息缓冲队列的线程间通信线程间的通信,关键采用send()与receive()来实现,通过发送一个文本信息来显示通信的过程,其过程为:send()函数:消息的发送者需要提供接收者的标识符,消息的长度以及消息正文的起始地址等信息,然后在发送原语里申请一空闲的消息缓冲区,用相应的信息来装配该消息缓冲区,并把它插入到接收者的消息队列中去。Receive()函数:消息的接受者必须给出发送者的标识符,接受区的起始地址等信息,然后从自己的消息队列中取得相应的发送者发送来的消息缓冲区,将消息正文复制到接受区中,并释放相应的消息缓冲区。源代码及解析如下#includestdlib.h#includestdio.h#includedos.h#defineGET_INDOS0x34#defineGET_CRIT_ERR0x5d06/*定义四个状态*/#definefinished0#definerunning1#defineready2#defineblocked3#defineTL3/*设置TL(时间片)时间为3*/#defineNTCB10/*NTCB是系统允许的最多任务数也就是进程数*/#defineNBUF5#defineNTEXT30/**********************声明变量********************/charfar*indos_ptr=0;charfar*crit_err_ptr=0;intcurrent;/*全部变量,始终等于正在执行的线程的内部标识符*/inttimecount=0;/*全局变量,等于上次调度至今的时间,在每次时钟中断发生时,timecount+1,通过它与TL课判断时间片是否到时,从而决定是否进行CPU调度*//********************定义数据结构********************/typedefint(far*codeptr)(void);/*定义codeptr函数指针*//*定义记录型信号量的数据结构*/typedefstruct{intvalue;structTCB*wq;}semaphore;semaphoremutexfb={1,NULL};/*互斥信号量*/semaphoresfb={NBUF,NULL};/*空闲缓冲队列的计数信号量*//*消息缓冲区的数据结构*/structbuffer{intsender;/*消息发送者的标识数*/intsize;/*消息长度=NTEXT个字节*/chartext[NTEXT];structbuffer*next;/指向下一个消息缓冲区的指针*/};structbuffer*freebuf;/*空闲消息缓冲队列,是临界资源,由NBUF个空闲的消息缓冲区组成*//*定义TCB数据结构*/structTCB{unsignedchar*stack;/*堆栈的起始地址*/unsignedss;/*堆栈的段址*/unsignedsp;/*堆栈的栈指针*charstate;/*线程的状态*/charname[10];/*线程的外部标示符*/structTCB*next;/*链接字段,把所有就绪的线程按某种方式排成一显式队列,如优先权从高到底的队列*/structbuffer*mq;/*消息队列队首指针*/semaphoremutex;/*消息队列的互斥信号量*/semaphoresm;/*消息队列计数信号量*/intvalue;}tcb[NTCB];/*NTCB是系统允许的最多任务数*//*现场保护和恢复中要用到的一个数据结构*/structint_regs{unsignedbp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags,off,seg;};/**************************声明函数*************************/intDosBusy(void);voidInitInDos(void);voidInitTcb(void);/*对TCB的初始化*/intcreate(char*name,codeptrcode,intstacklen);voidover(void);/*撤销线程,归还所占资源*/voidinterrupt(*old_int8)(void);/*原来的时间中断程序,需要先声明*/voidinterruptnew_int8(void);/*因时间片到时而引起的调度由new_int8()函数来完成*/voidinterruptswtch(void);/*其他原因引起的CPU调度由函数swtch()完成*/voidtcb_state(void);/*输出所有线程的状态信息*/intall_finished(void);voidp(semaphore*sem);/*信号量P操作*/voidv(semaphore*sem);/*信号量V操作*//*********************函数的实现*********************//*******InitInDos函数的实现********/voidInitInDos(void){unionREGSregs;structSREGSsegregs;/*获得INDOSflag的地址*/regs.h.ah=GET_INDOS;intdosx(®s,®s,&segregs),indos_ptr=MK_FP(segregs.es,regs.x.bx);/*gettheaddressofCRIT_ERRflag*/if(_osmajor3)crit_err_ptr=indos_ptr+1;elseif(_osmajor==3&&_osminor==0)crit_err_ptr=indos_ptr-1;else{regs.x.ax=GET_CRIT_ERR,intdosx(®s,®s,&segregs);crit_err_ptr=MK_FP(segregs.ds,regs.x.si);}}/*************DosBusy函数的实现************/intDosBusy(void){if(indos_ptr&&crit_err_ptr)return(*indos_ptr||*crit_err_ptr);elsereturn(-1);}/************InitTcb函数的实现*************//*对TCB进行初始化*/voidInitTcb(void){inti;for(i=1;iNTCB;i++){tcb[i].stack=NULL;tcb[i].state=finished;strcpy(tcb[i].name,'\0');tcb[i].mq=NULL;tcb[i].sm.value=0;/*消息队列计数信号量*/tcb[i].mutex.value=1;/*缓冲区的互斥信号量*/}}/*************create函数的实现****************//*创建一对应于函数name(外部标识符)的线程*/intcreate(char*name,codeptrcode,intstacklen){inti;char*p;structint_regs*pt;/*第一步:寻找空白的TCB*/for(i=1;iNTCB;i++){if(tcb[i].state==finished)break;}/*第二步:申请线程的私有堆栈内存空间,分配stacklen个字节长度的内存空间,利用malloc函数返回内存地址指针指向该内存空间,所返回的值是该内存空间的起始地址*/p=(char*)malloc(stacklen*sizeof(char));/*获得堆栈的内存空间的高地址指针*/p=p+stacklenpt=(structint_regs*)p;pt--;pt-flags=0x200;/*flags寄存器的允许中断位*/pt-cs=FP_SEG(code);/*代码段的段地址*/pt-ip=FP_OFF(code);/*代码段的段内偏移地址*/pt-ds=_DS;/*数据段的段地址*/pt-es=_ES;/*附加数据段的段地址*/pt-off=FP_OFF(over);/*撤销线程代码的偏移地址*/pt-seg=FP_SEG(over);/*撤销线程代码的段址*//*第四步:初始化线程的控制块TCB*/strcpy(tcb[i].name,name);/*填入线程的外部标识符*/tcb[i].state=ready;/*将线程的状态置成就绪态*/tcb[i].stack=p-stacklen;/*私有堆栈的起始地址*/tcb[i].ss=FP_SEG(pt);/*当前线程的段地址*/tcb[i].sp=FP_OFF(pt);/*当前线程的栈顶指针*/returni;/*返回线程的内部标示符*/}/************new_int8函数的实现***************//*系统调度,即时间中断到达后,判断时间片到后才运行,调用老的时钟中断*/voidinterruptnew_int8(void){inti;(*old_int8)();/*调用原来的时钟中断服
本文标题:基于线程的多任务调度系统的设计与实现实验报告
链接地址:https://www.777doc.com/doc-2537159 .html