基于线程的多任务调度系统的设计及实现报告实验报告Word文档下载推荐.docx
《基于线程的多任务调度系统的设计及实现报告实验报告Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《基于线程的多任务调度系统的设计及实现报告实验报告Word文档下载推荐.docx(23页珍藏版)》请在冰点文库上搜索。
send()函数:
消息的发送者需要提供接收者的标识符,消息的长度以及消息正文的起始地址等信息,然后在发送原语里申请一空闲的消息缓冲区,用相应的信息来装配该消息缓冲区,并把它插入到接收者的消息队列中去。
Receive()函数:
消息的接受者必须给出发送者的标识符,接受区的起始地址等信息,然后从自己的消息队列中取得相应的发送者发送来的消息缓冲区,将消息正文复制到接受区中,并释放相应的消息缓冲区。
源代码及解析如下
#include<
stdlib.h>
stdio.h>
dos.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;
/*消息队列计数信号量*/
}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(&
regs,&
segregs),
indos_ptr=MK_FP(segregs.es,regs.x.bx);
/*gettheaddressofCRIT_ERRflag*/
if(_osmajor<
3)
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(&
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);
else
return(-1);
/************InitTcb函数的实现*************/
/*对TCB进行初始化*/
voidInitTcb(void){
inti;
for(i=1;
i<
NTCB;
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){
char*p;
structint_regs*pt;
/*第一步:
寻找空白的TCB*/
if(tcb[i].state==finished)
break;
/*第二步:
申请线程的私有堆栈内存空间,分配stacklen个字节长度的内存空间,利用malloc函数返回内存地址指针指向该内存空间,
所返回的值是该内存空间的起始地址*/
p=(char*)malloc(stacklen*sizeof(char));
/*获得堆栈的内存空间的高地址指针*/
p=p+stacklen
pt=(structint_regs*)p;
pt--;
pt->
flags=0x200;
/*flags寄存器的允许中断位*/
cs=FP_SEG(code);
/*代码段的段地址*/
ip=FP_OFF(code);
/*代码段的段内偏移地址*/
ds=_DS;
/*数据段的段地址*/
es=_ES;
/*附加数据段的段地址*/
off=FP_OFF(over);
/*撤销线程代码的偏移地址*/
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){
(*old_int8)();
/*调用原来的时钟中断服务程序*/
timecount++;
/*每次发生中断时加1*/
if(timecount>
=TL){/*时间片到时*/
if(DosBusy())/*如果Dos忙*/
return;
disable();
/*关中*/
/*保护正在执行的线程current的现场,暂停它的执行*/
tcb[current].ss=_SS;
tcb[current].sp=_SP;
if(tcb[current].state==running)/*将执行状态变为就绪状态,暂停执行*/
tcb[current].state=ready;
/*找到以新的就绪线程*/
for(i=1;
if(tcb[i].state==ready&
i!
=current)/*找到除了当前线程的其他就绪线程*/
break;
}
/*如果没有找到就绪线程,那么就回复当前线程,继续执行*/
if(i>
=NTCB){
if(tcb[current].state==ready)
tcb[current].state=running;
enable();
/*如果超出了NTCB则恢复现场然后返回*/
/*如果找到就绪线程,那么恢复线程i的现场,把CPU分配给它*/
_SS=tcb[i].ss;
_SP=tcb[i].sp;
tcb[i].state=running;
/*置线程i为现有线程,并且重新开始计时*/
current=i;
timecount=0;
enable();
/*开中*/
return;
/*********swtch函数的实现************/
/*针对Swtch()函数的实现:
由于它是解决由其他因素所引起的CPU调度,在这个实现过程,只需要判断线程的执行状态即可,其他阻塞等状态不需要进行判断,或者可以直接对当前线程的现场进行保护,然后寻找就绪线程,分配CPU以及现场进行执行*/
/*Find()函数是为了寻找就绪线程而且是优先权大的线程(根据优先数越大,优先权越小的思想,在TCB设置以优先数,然后进行选择)*/
intFind()
inti,j;
for(i=0;
i++)
if(tcb[i].state==ready&
i!
=current)
break;
if(i==NTCB)
return-1;
for(j=i+1;
j<
j++)
{
if(tcb[j].state==ready&
j!
if(tcb[j].value>
tcb[i].value)
i=j;
/*swtch()调度,手工调度才能运行,处理因其他因素引起的中断*/
voidinterruptswtch(void)
i=Find();
if(i<
0)
i=0;
disable();
tcb[current].ss=_SS;
tcb[current].sp=_SP;
if(tcb[current].state==running)
tcb[current].state=ready;
_SS=tcb[i].ss;
_SP=tcb[i].sp;
tcb[i].state=running;
current=i;
enable();
/****************线程的阻塞和唤醒的实现****************/
/**(阻塞)block函数的实现**/
voidblock(structTCB**qp){
structTCB*tp;
tp=*qp;
tcb[current].state=blocked;
/*首先要将当前线程的状态置为阻塞状态*/
/*需要将线程插入到指定的阻塞队列未尾,并重新进行CPU调度*/
(*qp)->
next=NULL;
if(tp==NULL)
tp=&
tcb[current];
/*由于tp是一个指针,所以操作的是指针*/
while(tp->
next!
=NULL)
tp=tp->
next;
tp->
next=&
/*将阻塞线程插入到队尾*/
swtch();
/*并重新进行CPU调度*/
/**(唤醒)wakeup_first函数的实现**/
voidwakeup_first(structTCB**qp){
/*寻找阻塞线程,因为线程状态的改变需要在TCB中修改,所以需要知道阻塞队列里面需要唤醒的线程对应TCB数组里面的哪一个*/
if(strcmp(tcb[i].name,(*tp->
next).name)==0){/*如果两个外部标示符一样说明找到需要唤醒的线程*/
tcb[i].state=ready;
/*将其状态改为就绪状态*/
/***************线程的同步和互斥的实现****************/
/*用记录型信号量机制实现同步与互斥*/
/**对信号量的P操作**/
voidp(semaphore*sem){
structTCB**qp;
/*设置一个指向TCB链表的二级指针*/
/*关中断*/
sem->
value=sem->
value-1;
/*记录型信号量的value值减1*/
if(sem->
value<
0){/*如果记录型信号量的值小于0*/
qp=&
(sem->
wq);
/*那么将qp指针指向sem信号量的阻塞队列*/
block(qp);
/*阻塞相应进程到阻塞队列*/
/**对信号量的V操作**/
voidv(semaphore*sem){
qp=&
value+1;
=0){
wakeup_first(qp);
/***************消息缓冲队列的线程间的通信*************/
/**初始化消息队列**/
voidInitBuf(void){
structbuffer*freebuf,*temp;
freebuf=(structbuffer*)malloc(sizeof(structbuffer));
/*申请空间*/
temp=freebuf;
=NBUF;
temp=(structbuffer*)malloc(sizeof(structbuffer));
temp=temp->
/**从空闲消息缓冲队列头上取下一缓冲区,返回指向该缓冲区的指针**/
structbuffer*getbuf(void){
structbuffer*buff;
buff=freebuf;
/*空闲消息缓冲头*/
freebuf=freebuf->
returnbuff;
/**将buff所指的缓冲区插到*mq所指的缓冲队列尾**/
voidinsert(structbuffer**mq,structbuffer*buff){
structbuffer*temp;
if(buff==NULL)
return;
buff->
if(*mq==NULL)
*mq=buff;
temp=*mq;
while(temp->
temp=temp->
temp->
next=buff;
/***将地址a开始的size个字节发送给外部标示符为receiver的线程***/
voidsend(char*receiver,char*a,intsize){
inti,id=-1;
/*原语要关中断*/
/*首先需要进行搜索接受进程*/
if(strcmp(receiver,tcb[i].name)==0){
id=i;
break;
/*如果没有收到,那么就显示错误,没有接收进程*/
if(id==-1){
printf("
Error:
Receivernotexist!
\n"
return;
\n%ssend%samessage:
"
tcb[current].name,receiver);
%s\n"
a);
p(&
sfb);
/*sfb为空闲缓冲区队列的计数信号量,为全局变量*/
mutexfb);
/*mutexfb为互斥信号量*/
buf