杭电操作系统课程设计1_第1页
杭电操作系统课程设计1_第2页
杭电操作系统课程设计1_第3页
杭电操作系统课程设计1_第4页
杭电操作系统课程设计1_第5页
已阅读5页,还剩43页未读, 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、基于基于DOS的多任务系统的实现的多任务系统的实现 主要任务主要任务 线程的创建和撤消线程的创建和撤消 FCFS调度调度 时间片轮转调度时间片轮转调度 同步机制的实现同步机制的实现 消息缓冲队列消息缓冲队列 通信机制的实现通信机制的实现int current;main() /* 创建创建0#线程线程 */ strcpy(, main); tcb0.state=RUNNING; current=0; /* 创建创建1#、2#线程线程 */ create(f1,(codeptr)f1,1024); create(f2,(codeptr)f2,1024); /* 启动多个线程的并发

2、执行启动多个线程的并发执行 */ swtch(); printf(n Multi_task system terminated. n); void f1(void) putchar(a); . void f2(void) putchar(b); . 编程环境编程环境 16位的位的DOS模式:内存地址模式:内存地址20位位 Turbo C 2.0 地址线为地址线为20根,即物理地址为根,即物理地址为20位;位; 内存空间不超过内存空间不超过1M; 字长为字长为16位;位; 分段存储管理方式:分段存储管理方式: 每段长度不超过每段长度不超过216B; 段表用寄存器的方式来实现:段表用寄存器的方式来

3、实现:CS代码段内存基址代码段内存基址DS数据段内存基址数据段内存基址SS堆栈段内存基址堆栈段内存基址DOS规定:段在内存的起始地址的低规定:段在内存的起始地址的低4位必须为位必须为0。内存内存datastackcode代码代码数据数据堆栈堆栈的高的高16位位的高的高16位位的高的高16位位0L1-10L2-10L3-101M-1 二维的逻辑地址二维的逻辑地址: seg:off 逻辑地址逻辑地址 seg24+off 物理地址物理地址ADOS系统,系统,C语言中地址的两种语言中地址的两种表达方式:表达方式: 指针指针 :如:如 char *p; 用两个无符号整数用两个无符号整数seg:off分别

4、表示段内存基址的高分别表示段内存基址的高16位,段内偏移位,段内偏移: 如如 0X100:0X20Turbo C提供了宏函数,使两种提供了宏函数,使两种方式之间可以互相转化:方式之间可以互相转化:p=MK_FP(seg,off);seg=FP_SEG(p);off=FP_OFF(p).data00X20 A内存内存0X1000p0X1020char c=A;char *p; p=&c;c0X100:0X20线程的概念线程的概念线程线程是进程内是进程内一个一个相对独立的相对独立的运行单位运行单位,一个进,一个进程可以有一个或多个线程(至少有一个),这些程可以有一个或多个线程(至少有一个)

5、,这些线程共享这个进程的代码、数据及大部分管理信线程共享这个进程的代码、数据及大部分管理信息,但每个线程有自己的程序计数器、堆栈和线息,但每个线程有自己的程序计数器、堆栈和线程控制块。程控制块。 拥有资源的基本单位拥有资源的基本单位进程;进程; 执行的基本单位(即执行的基本单位(即CPU调度和分派的单位调度和分派的单位)线程。线程。int current;main() /* 创建创建0#线程线程 */ strcpy(, main); tcb0.state=RUNNING; current=0; /* 创建创建1#、2#线程线程 */ create(f1,(codeptr)f1

6、,1024); create(f2,(codeptr)f2,1024); /* 启动多个线程的并发执行启动多个线程的并发执行 */ swtch(); printf(n Multi_task system terminated. n); void f1(void) putchar(a); . void f2(void) putchar(b); . 代码段代码段数据段数据段进程和线程进程和线程堆栈堆栈tcb0堆栈堆栈tcb1堆栈堆栈tcb2mainf1f2currenttcb 线程线程0 线程线程1 线程线程2线程线程0是进程的首个线程,当进程首次得到是进程的首个线程,当进程首次得到CPU时,线时

7、,线程程0就处于执行状态。就处于执行状态。线程线程1、线程、线程2要通过线程调度函数,才能得到要通过线程调度函数,才能得到CPU。堆栈的概念堆栈的概念 堆栈其实是一段内存空间;堆栈其实是一段内存空间; 堆栈中最后压入数据的那个单元叫栈顶,该单元的地堆栈中最后压入数据的那个单元叫栈顶,该单元的地址就是栈顶指针;址就是栈顶指针; CPU执行很多指令时都会用到堆栈,比如:执行很多指令时都会用到堆栈,比如: push 指令;指令; pop指令;指令; 函数调用指令函数调用指令 call; 函数返回指令函数返回指令ret和中断返回指令和中断返回指令 iret; int指令指令 等等。等等。 函数调用的参

8、数及返回地址,程序的局部变量等信息函数调用的参数及返回地址,程序的局部变量等信息通常都被保存在进程的堆栈中。通常都被保存在进程的堆栈中。 堆栈的概念堆栈的概念 传统的进程由传统的进程由PCB、代码段、数据段和堆栈段四部分、代码段、数据段和堆栈段四部分组成,但很多系统中把堆栈包含在数据段中。组成,但很多系统中把堆栈包含在数据段中。 引入线程后,每个线程都必须有自己的私有堆栈。引入线程后,每个线程都必须有自己的私有堆栈。 CPU切换时,要进行堆栈的切换,从而使新进程(或切换时,要进行堆栈的切换,从而使新进程(或新线程)可以把信息保存在自己的堆栈中,而不是老新线程)可以把信息保存在自己的堆栈中,而不

9、是老进程(或线程)的堆栈中。进程(或线程)的堆栈中。 CPU正在使用的堆栈被称作现行堆栈,它的栈顶指针正在使用的堆栈被称作现行堆栈,它的栈顶指针存放在存放在CPU的栈顶指针寄存器中(如的栈顶指针寄存器中(如SS:ESP)。)。bx起始地址起始地址结束地址结束地址栈顶指针栈顶指针ss:esp堆栈堆栈100堆栈的概念堆栈的概念36堆栈堆栈起始地址起始地址结束地址结束地址栈顶指针栈顶指针ss:esp100起始地址起始地址结束地址结束地址栈顶指针栈顶指针ss:esp堆栈堆栈100设设ax=36:压栈指令压栈指令push ax出栈指令出栈指令pop bxesp先减先减2个字节;个字节;再将操作数写到再将

10、操作数写到对应的单元中。对应的单元中。先从对应的单元先从对应的单元中取出信息;中取出信息;再将再将 esp加上加上2个个字节;字节;3636X86中信息是从高端往低端入栈的。中信息是从高端往低端入栈的。线程控制块线程控制块#define NTCB 5 struct TCB unsigned char *stack; /* 线程堆栈的起始地址线程堆栈的起始地址 */ unsigned ss; /* 堆栈段址堆栈段址 */ unsigned sp; /* 堆栈指针堆栈指针 */ char state; /* 线程状态:执行、就绪、阻塞线程状态:执行、就绪、阻塞 */ char name10; /*

11、 线程的外部标识符线程的外部标识符 */ tcbNTCB; /*NTCB是系统允许的最多任务数是系统允许的最多任务数*/栈顶指针栈顶指针用用C C指针来表示指针来表示用段地址和偏移用段地址和偏移(即(即2 2个无符号个无符号整数)表示整数)表示线程控制块线程控制块 #define FINISHED 0 /* 表示线程处于终止态表示线程处于终止态 或或 TCB是空闲状态是空闲状态 */ #define RUNNING 1 /* 表示线程处于运行态表示线程处于运行态 */ #define READY 2 /* 表示线程处于就绪态表示线程处于就绪态 */ #define BLOCKED 3 /* 表

12、示线程处于阻塞态表示线程处于阻塞态 */ CPU切换切换 CPU的指令计数器(的指令计数器(X86中的中的CS,IP寄存器)中保存寄存器)中保存有下一条要执行的机器指令的地址;有下一条要执行的机器指令的地址; 每次每次CPU取指令后,指令计数器的值被加上所取指令取指令后,指令计数器的值被加上所取指令的字节数,调整为下一条指令的地址;的字节数,调整为下一条指令的地址; 修改指令计数器的方法:修改指令计数器的方法: 跳转指令(如跳转指令(如JMP,JNE等)等) 函数调用指令函数调用指令 中断。中断。 CPU切换切换 跳转指令跳转指令JMP的格式:的格式: JMP 操作数操作数段内转移段内转移段间

13、转移段间转移段间转移段间转移:只需修改:只需修改IP的值;的值;:需同时修改:需同时修改CS和和IP的值;的值;CS:1000hCS:1000hIP:100hIP:100hCS:CS:不变不变IP:800hIP:800hCS:1000hCS:1000hIP:100hIP:100hCS:1500hCS:1500hIP:0IP:01500h: 0 L2:段内转移段内转移1000h: 01000h:800h1000h:100h JMP L1L1:1000h: 01000h:100hmov word ptr bx+2,1500hmov word ptr bx,0JMP far ptr bx ; CPU

14、切换切换 函数调用指令函数调用指令CALL的格式:的格式: CALL 操作数操作数段内调用段内调用段间调用段间调用 call funfun:段内调用段内调用seg1: 0seg1:off2seg1:off1ret CS不用压栈不用压栈 IP压栈;压栈; IPfun。 IP栈顶的返址栈顶的返址即把函数返回地址即把函数返回地址seg1:seg1:off1off1压栈压栈即从栈顶弹出函数的返回地址即从栈顶弹出函数的返回地址段间调用则先将段间调用则先将CS压栈,再将压栈,再将IP压栈,然后压栈,然后将子函数入口地址赋值给将子函数入口地址赋值给CS和和IP。ret返回时返回时则从依次从栈顶弹出则从依次从

15、栈顶弹出IP,CS。 CPU切换切换中断中断 -当当CPU在执行指令在执行指令1的期间收到的期间收到8号中断信号,并在该指号中断信号,并在该指令执行完后响应中断时,硬件将完成下列动作:令执行完后响应中断时,硬件将完成下列动作: 将将flags寄存器压栈;寄存器压栈; 将将CS,IP寄存器压栈;寄存器压栈; 从中断向量表的第从中断向量表的第8个向量中获得个向量中获得8#中断处理程序中断处理程序的入口地址,将它们装入的入口地址,将它们装入CS,IP中。中。-Iret指令将从栈顶依次弹出指令将从栈顶依次弹出ip,cs,flags。CS:IP指令指令1指令指令2被中断的程序被中断的程序8#中断处理程序

16、中断处理程序iretCS8:IP8中断向量中断向量0中断向量中断向量8IP0CS0IP8CS8中断向量表中断向量表00000h00004h003FFh00020h保存被中断程序的现场保存被中断程序的现场转去执行中断转去执行中断处理程序处理程序CS,IP:指令计数器,用于:指令计数器,用于存放要执行的下一条指令的地址存放要执行的下一条指令的地址SS,SP:栈顶指针寄存器;:栈顶指针寄存器;DS:数据段段址寄存器;:数据段段址寄存器;Flags:标志寄存器:标志寄存器ES:附加段寄存器:附加段寄存器SI、DI:变址寄存器:变址寄存器BP:指针寄存器:指针寄存器 AX、BX、CX、DX AH、AL、

17、BH、BL、CH、CL、DH、DL(8b)X86实模式的寄存器实模式的寄存器通用数据寄存器通用数据寄存器程序执行时用程序执行时用来保存常用的来保存常用的中间结果中间结果IFCFPFAFZFSFOFTF DF控制标志控制标志状态标志状态标志0进进位位2奇奇偶偶4辅辅助助进进位位6零零7符符号号11溢溢出出9中中断断允允许许10方方向向8陷陷阱阱CPU切换时需要保存的现场信息切换时需要保存的现场信息 flags,cs,ip,ax,bx,cx,dx,es,ds,si,di,bp,ss,sp 共14个16位的寄存器。 JMP指令不保存任何现场; CALL指令只保存cs,ip两个寄存器; 中断则保存fl

18、ags,cs,ip三个寄存器。CSipmain() fun(); L: void interrupt fun(void) Turbo C 的interrupt类型函数pushfcall _funpushaxpushbxpushcxpushdxpushespushdspushsipushdipushbppopbp pushaxiret_fun:堆栈堆栈SS:SPflagsbpdisidsesdxcxbxaxSS:SPCSipTurbo C 的interrupt类型函数堆栈堆栈flagsbpdisidsesdxcxbxaxSS:SP可见,可见,Turbo C中调用中调用interrupt类型函数时

19、类型函数时可以将可以将CPU现场中的:现场中的:flags,cs,ip,ax,bx,cx, dx,es,ds,si,di,bp寄存器依次压入堆栈,其中寄存器依次压入堆栈,其中flags,cs,ip在该函数调用时压入堆栈,而剩余在该函数调用时压入堆栈,而剩余的的ax,bx,cx,dx,es,ds,si,di, bp则由被调用的则由被调用的interrupt函数压入栈。函数压入栈。14个寄存器的个寄存器的12个已个已被保存到堆栈中,只剩下被保存到堆栈中,只剩下SS,SP这两个寄这两个寄存器还未被保存。存器还未被保存。CPU调度函数将借助于调度函数将借助于interrupt类型函数来类型函数来实现,

20、在函数中将剩下的实现,在函数中将剩下的SS,SP寄存器的寄存器的值保存在值保存在TCB中,从而完成整个现场的保存。中,从而完成整个现场的保存。Turbo C 的伪变量所谓的伪变量是一个和给定寄存器相一致的简单所谓的伪变量是一个和给定寄存器相一致的简单的标识符,通过它们,我们可以在的标识符,通过它们,我们可以在C 语言程序中语言程序中直接访问相应的寄存器直接访问相应的寄存器。 伪变量伪变量 类型类型 寄存器寄存器 通常用处通常用处 _AX 无符号整型无符号整型 AX 通用累加器通用累加器 _AL 无符号字符型无符号字符型 AL AX的低字节的低字节 _AH 无符号字符型无符号字符型 AH AX的

21、高字节的高字节 _BX 无符号整型无符号整型 BX 通用变址器通用变址器 _BL 无符号字符型无符号字符型 BL BX的低字节的低字节 _BH 无符号字符型无符号字符型 BH BX的高字节的高字节 _CX 无符号整型无符号整型 CX 通用计数和循环通用计数和循环 _CL 无符号字符型无符号字符型 CL CX的低字节的低字节 _CH 无符号字符型无符号字符型 CH CX的高字节的高字节 _DX 无符号整型无符号整型 DX 通用存放数据通用存放数据 _DL 无符号字符型无符号字符型 DL DX的低字节的低字节 _DH 无符号字符型无符号字符型 DH DX的高字节的高字节 Turbo C 的伪变量

22、伪变量伪变量 类型类型 寄存器寄存器 通常用处通常用处 _CS 无符号整型无符号整型 CS 代码段地址代码段地址 _DS 无符号整型无符号整型 DS 数据段地址数据段地址 _SS 无符号整型无符号整型 SS 堆栈段地址堆栈段地址 _ES 无符号整型无符号整型 ES 附加段地址附加段地址 _SP 无符号整型无符号整型 SP 堆栈指针(对堆栈指针(对SS的偏移)的偏移) _BP 无符号整型无符号整型 BP 基址指针基址指针 _DI 无符号整型无符号整型 DI 用于寄存器变量用于寄存器变量 _SI 无符号整型无符号整型 SI 用于寄存器变量用于寄存器变量 CPU调度函数swtch()void int

23、errupt swtch(void) disable(); /*1*/ tcbold.ss=_SS; /*2*/ tcbold.sp=_SP; /*3*/ new=find(); /*4*/ _SS=tcbnew.ss; /*5*/ _SP=tcbnew.sp; /*6*/ enable(); /*7*/main() create(f1,(codeptr)f1,1024); create(f2,(codeptr)f2,1024); swtch(); 假设新线程为假设新线程为1#线程线程f1,它的现场已按上述要求保存在堆栈和,它的现场已按上述要求保存在堆栈和TCB1中,现在正在执行的是中,现在正

24、在执行的是0#线程线程main,它的现场正装在,它的现场正装在CPU的寄存器中。当的寄存器中。当main调用调用swtch()时:时:flagscscsCPU调度函数swtch() 当main执行swtch()时:ipf1的堆栈的堆栈flagsbpdisidsesdxcxbxaxtcb1.ss:tcb1.spipmain的堆栈的堆栈SS:SP pushf;call _swtch; 将flags,cs,ip压栈,其中cs,ip是call _swtch指令后的那条指令的地址; 转去执行_swtch函数。flagsbpdisidsesdxcxbxaxcscsCPU调度函数swtch() 当执行swt

25、ch函数体时:ipf1的堆栈的堆栈flagsbpdisidsesdxcxbxaxtcb1.ss:tcb1.spipmain的堆栈的堆栈SS:SPSS:SP由于它是由于它是interrupt类型的函数,类型的函数,所以编译将自动在函数入口处添所以编译将自动在函数入口处添加加push ax,push bp指令;所指令;所以会将以会将main的现场中的的现场中的ax,bp保存进堆栈;保存进堆栈;然后再由然后再由2,3两条语句将当前栈两条语句将当前栈顶保存到顶保存到tcb0中;中;tcb0.ss:tcb0.spflagsflagsbpdisidsesdxcxbxaxcscsCPU调度函数swtch()

26、 当执行swtch函数体时:ipf1的堆栈的堆栈bpdisidsesdxcxbxaxtcb1.ss:tcb1.spipmain的堆栈的堆栈SS:SP接着由语句接着由语句4通过某种调度算法通过某种调度算法找到新线程,如找到新线程,如1#线程;线程;再由再由5,6两条语句将新线程的堆两条语句将新线程的堆栈置为栈置为CPU的当前栈;的当前栈;在函数结束前,将执行在函数结束前,将执行pop bp;pop ax指令将指令将f1栈中的信栈中的信息弹出到相应寄存器中;息弹出到相应寄存器中;最后由最后由iret指令,依次将栈顶的指令,依次将栈顶的3个字弹出到个字弹出到ip,cs,flags寄存器中。寄存器中。

27、tcb0.ss:tcb0.spflagsbpdisidsesdxcxbxaxcsCPU调度函数swtch() 现在现在CPU中装的已经是中装的已经是f1的现场信息的现场信息,CPU将按将按f1的要求去取下一条指令的要求去取下一条指令来执行,也就是说来执行,也就是说CPU已经从已经从main线线程切换到程切换到f1线程。线程。f1的堆栈的堆栈tcb1.ss:tcb1.spipmain的堆栈的堆栈SS:SPtcb0.ss:tcb0.spflagscsipbpdisidsesdxcxbxaxCPU调度函数swtch()void interrupt swtch(void) disable(); tcb

28、old.ss=_SS; tcbold.sp=_SP; new=find(); _SS=tcbnew.ss; _SP=tcbnew.sp; enable();main() create(f1,(codeptr)f1,1024); create(f2,(codeptr)f2,1024); swtch(); swtch()调用过程能被中断吗?调用过程能被中断吗?flagsflagsbpdisidsesdxcxbxaxcscsCPU调度函数swtch() 当执行swtch函数体时:ipf1的堆栈的堆栈bpdisidsesdxcxbxaxtcb1.ss:tcb1.spipmain的堆栈的堆栈SS:SP如

29、果不被中断,那么如果不被中断,那么CPU的栈顶的栈顶指针将正确地指向线程指针将正确地指向线程f1的栈顶。的栈顶。如果在虚线的位置被中断了,那如果在虚线的位置被中断了,那么栈顶指针将使用么栈顶指针将使用f1栈的段地址,栈的段地址, 但偏移仍然是但偏移仍然是main栈栈顶的偏移栈栈顶的偏移地址,栈顶指针将指向错误的位地址,栈顶指针将指向错误的位置。置。tcb0.ss:tcb0.sp错误错误正确正确CPU调度函数swtch()void interrupt swtch(void) disable(); tcbold.ss=_SS; tcbold.sp=_SP; new=find(); _SS=tcbn

30、ew.ss; _SP=tcbnew.sp; enable();main() create(f1,(codeptr)f1,1024); create(f2,(codeptr)f2,1024); swtch(); disable()enable():关中,相当于汇编指令:关中,相当于汇编指令cli;:开中相当于汇编指令:开中相当于汇编指令sti;Turbo c 提供了两个函数提供了两个函数swtch()中的中的disable()和和enable()保证黄色区域内的程序不会被中断保证黄色区域内的程序不会被中断.代码段代码段数据段数据段线程的创建线程的创建堆栈堆栈tcb0堆栈堆栈tcb1mainf1f

31、2currenttcb 线程线程0 线程线程1如何创建一个线程,让它去运行如何创建一个线程,让它去运行f1(),而且当,而且当f1()结束时,结束时,该线程能自动终止?该线程能自动终止?第一步第一步第二步第二步第三步第三步现场现场信息信息指令计数指令计数器器数据段地数据段地址址:堆栈初始化和:堆栈初始化和TCB的初始化的初始化栈顶指针栈顶指针线程的创建线程的创建 typedef int (far *codeptr)(void); int create(char *name,codeptr code,int stacklen);线程的外线程的外部标识符部标识符线程对应线程对应的函数的函数线程的私

32、线程的私有栈长度有栈长度main() create(f1,(codeptr)f1,1024); create(f2,(codeptr)f2,1024); swtch(); 线程的创建线程的创建int create(char *name,codeptr code,int stacklen);创建的过程:创建的过程: 为新线程分配一空闲的线程控制块;为新线程分配一空闲的线程控制块; 为新线程的私有堆栈分配内存空间;为新线程的私有堆栈分配内存空间; 在堆栈的栈顶存入线程的初始现场信息,即初始化新在堆栈的栈顶存入线程的初始现场信息,即初始化新线程的私有堆栈,线程的私有堆栈, 初始化线程控制块,即填入线

33、程的外部标识符,设置初始化线程控制块,即填入线程的外部标识符,设置好线程私有堆栈的始址、堆栈的段址和栈顶指针,将好线程私有堆栈的始址、堆栈的段址和栈顶指针,将线程的状态置成就绪态。线程的状态置成就绪态。 最后,返回新线程的内部标识符。最后,返回新线程的内部标识符。malloc(stacklen):malloc(stacklen):申请申请stacklenstacklen字节的内存空间,字节的内存空间,返回分配到的内存空间的起始地址。返回分配到的内存空间的起始地址。ipbpdisidsesdxcxbxaxflagscsf1的堆栈的堆栈tcb1.ss:tcb1.sp线程的创建线程的创建int cr

34、eate(char *name,codeptr code,int stacklen); 如何布置初始现场如何布置初始现场 现场信息必须放在堆栈的栈顶,即堆栈的高端现场信息必须放在堆栈的栈顶,即堆栈的高端; 现场信息必须严格按照规定的格式保存;现场信息必须严格按照规定的格式保存; 现场信息中指令计数器现场信息中指令计数器cs:ip必须为必须为code所指向的函数的首条指令的地址的段址和所指向的函数的首条指令的地址的段址和偏移:偏移: FP_SEG(code), FP_OFF(code), DS必须为进程数据段的段地址。必须为进程数据段的段地址。 Main的数据段的段地址:的数据段的段地址:_DS

35、 以后线程运行时,必须允许以后线程运行时,必须允许CPU能响应中能响应中断,即断,即flags的的IF必须置必须置1。 0 x2000 x200flagipbpdisidsesdxcxbxaxf1的堆栈的堆栈tcb1.ss:tcb1.sp线程的创建线程的创建int create(char *name,codeptr code,int stacklen); 如何布置初始现场如何布置初始现场 char *p; int *intp; p=malloc(stacklen); p=p+stacklen; intp=(int*)p; intp-; *intp=0 x200; struct int_regs

36、 unsigned bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flags; *xp;malloc()malloc()的返回值的返回值p pp p intpintp intpcs定义成一个结构定义成一个结构 xp xp=(struct int_regs *)p; xp-; xp-flags=0 x200; 线程的终止线程的终止 destroy(int i); /* 终止终止tcbi对应的线程对应的线程 */终止的过程:终止的过程: 释放线程的私有栈空间;释放线程的私有栈空间; 释放释放TCB; 如果需要调度,则调用如果需要调度,则调用swtch()重新进行()重新进行CP

37、U调度调度线程执行完对应函数的最后一条指令线程执行完对应函数的最后一条指令retret后,如何做后,如何做到自动终止呢?到自动终止呢?free(char *p) 线程的终止线程的终止线程运行完后自动终止线程运行完后自动终止 ret指令执行时,会从当前栈栈顶弹出两个字到指令执行时,会从当前栈栈顶弹出两个字到IP,CS中,这两个字通常是通过函数调用压进去的函数中,这两个字通常是通过函数调用压进去的函数返回地址;返回地址; over()函数:它的功能是通过函数:它的功能是通过“destroy(current);”调用来终止当前正在执行的线程。调用来终止当前正在执行的线程。 在每个线程创建时,保存初始

38、现场之前,先将在每个线程创建时,保存初始现场之前,先将over()的入口地址压入栈顶,然后再保存初始现场。那么,的入口地址压入栈顶,然后再保存初始现场。那么,线程对应的函数执行线程对应的函数执行ret指令时将会返回到指令时将会返回到over处,处,从而完成当前线程的终止,并重新调度从而完成当前线程的终止,并重新调度CPU的工作的工作。over()over()入口地址的保存工作也是在线程创建函数入口地址的保存工作也是在线程创建函数create()create()的堆栈初始化部分进行。的堆栈初始化部分进行。csipbpdisidsesdxcxbxaxflagsf1的堆栈的堆栈tcb1.ss:tcb

39、1.spoveripovercsdestroy(curent);over函数函数f1( )ret;f1线程创建完毕后,将处于就绪状线程创建完毕后,将处于就绪状态,它的私有栈如右图;态,它的私有栈如右图;f1线程首次被线程首次被swtch()选中时:选中时: swtch()恢复现场时,栈中的现场信恢复现场时,栈中的现场信息都将出栈到对应的息都将出栈到对应的CPU寄存器中寄存器中( 如:如:f1的入口地址被弹出到指令的入口地址被弹出到指令计数器中),栈顶指针将指向计数器中),栈顶指针将指向overip对应的单元。对应的单元。f1()执行,执行,f1私有栈的样子;私有栈的样子;Ret指令执行时,指令

40、执行时,overip被弹出到被弹出到CPU的的ip寄存器中,寄存器中,overcs被弹出被弹出到到CPU的的cs寄存器中;寄存器中;当前线程被终止,在终止动作的最当前线程被终止,在终止动作的最后将完成后将完成CPU的调度,选择另一个的调度,选择另一个线程执行。线程执行。CPU现现场场信信息息CS:IPvoid f1(void) int i,j,k; for(i=0;i40;i+) putchar(a); /*延时延时*/ for(j=0;j10000;j+) for(k=0;k10000;k+); void f2(void) int i,j,k; for(i=0;i30;i+) putchar(b); /*延时延时*/ for(j=0;j10000;j+) for(k=0;k10000;k+); 时间片轮转调度时间片轮转调度 DOS的时钟中断的时钟中断 中断源:定时器芯片;中断源:

温馨提示

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

评论

0/150

提交评论