Minix 进程调度代码详解
- 格式:docx
- 大小:23.40 KB
- 文档页数:4
MINIX 操作系统的启动过程与中断机制解析公维冰朱文俊(兰州大学数学与统计学院,甘肃兰州730000)摘要:MINIX 操作系统是一个面向教学的操作系统,它是第一个将所有源代码免费对外公布的系统,它的这个优点就为我们学习操作系统提供了很大的方便,我们可以通过学习源代码来更深刻的学习操作系统的基本原理。
系统的分层式结构,实现方式虽然简单,但是却给出了操作系统最基本的实现结构。
我们这里通过解析代码来说明MINIX2.0操作系统的中断机制是如何实现的,包括硬件中断,软件中断和异常中断。
关键词:MINIX2.0操作系统中断机制硬中断软中断异常中图分类号:TP31介绍MINIX 操作系统是一种与UNIX 操作系统兼容的小型操作系统,它最早是由计算机科学教育家的Tanenbaum 开发的。
与UNIX 相比,MINIX 的小巧和高度的模块化使其非常适合于操作系统教程,而其源代码的公开性又为操作系统研究者提供了极大的方便。
现在流行的LINUX 操作系统就是在开放的MINIX 操作系统基础上发展起来的。
在MINIX 操作系统家族中,MINIX1.0的设计基于UNIX V7标准,而MINIX2.0的设计则基于POSIX 标准,现己升级到了MINIX3。
我们将在第二节介绍MINIX2.0操作系统的整体结构,第三节是MINIX2.0操作系统的启动过程,第四节介绍MINIX2.0操作系统的中断机制,包括硬件中断机制,软件中断机制和异常机制,第五节我们给出结论。
2MINIX2.0操作系统的整体结构MINIX2.0操作系统整体实行分层结构,如下所示:第四层:用户进程层init 进程编译器编辑器其它用户进程第三层:服务器进程层内存管理器(mm)文件系统服务器(fs)网络服务器(nets)第二层:I/O 驱动任务层内存管理驱动硬盘驱动终端驱动时钟任务其它驱动任务第一层:操作系统最底层操作系统的启动,中断处理,进程调度等以上各层中层数越低就越底层,其中低层是高层的基础,高层依赖低层实现更高级和更复杂的功能。
1.Minix3中为每个进程分配的时间片,当进程的时间片用完后,将进行进程调度。
进程的时间片以时钟滴答为单位进行分配。
每次时钟中断,中断处理程序将减少当前进程的时间片。
当时间片减小到0时,进行进程调度,选择一个合适的进程来拥有CPU。
Minix3以每秒钟60次的频率进行时钟中断,即时钟中断处理程序每秒执行60次。
每次执行,减少当前进程的时间片:/* Get number of ticks and update realtime. */ticks = lost_ticks + 1; /* lost_ticks为BIOS中断所花费的时间 */lost_ticks = 0; /* lost_ticks清0 */realtime += ticks; /* 更新时间 */proc_ptr->p_user_time += ticks; /* 更新当前进程的user_time */if (priv(proc_ptr)->s_flags & PREEMPTIBLE) {/* 如果进程可被抢占,则减少时间片 */proc_ptr->p_ticks_left -= ticks;}if (! (priv(proc_ptr)->s_flags & BILLABLE)) {/* 如果当前进程能付费,则修改sys_time及减少时间片 */bill_ptr->p_sys_time += ticks;bill_ptr->p_ticks_left -= ticks;}如果时间片用完,则向clock_task发送通知。
因为该进程的时间片用完,需要重新调度,所以该进程就成为了上一个执行的进程。
if((next_timeout <= realtime)||(proc_ptr->p_ticks_left<= 0)) { /* 如果定时器到期或者进程时间片用完,则进行调度 */prev_ptr = proc_ptr; /* 当前进程成为上一次执行的进程 */lock_notify(HARDWARE, CLOCK); /* send notification */ /* 时间到期时发送通知给clock_task,由该函数进行后续处理 */}2.clock_task为时钟任务的主程序,用一个无限循环等待并处理时钟中断处理程序发来的通知。
进程调度算法代码进程调度算法是操作系统中的一种重要机制,它决定了在多道程序环境下,如何安排各个进程的执行顺序和时间片。
不同的进程调度算法有不同的实现方式和优缺点,本文将就常见的几种进程调度算法进行详细介绍。
1. 先来先服务(FCFS)先来先服务是最简单、最直观的进程调度算法。
它按照进程到达时间的先后顺序进行调度,即先到达的进程先执行。
当一个进程开始执行后,直到该进程执行完毕或者发生某些阻塞事件才会切换到另一个进程。
FCFS算法代码如下:```void FCFS(){int i;for(i=0;i<n;i++){run(p[i].need_time);if(i!=n-1){wait(p[i+1].arrive_time-p[i].arrive_time-p[i].need_time); }}}```其中,p数组表示所有需要执行的进程,n表示总共有多少个需要执行的进程。
run函数表示运行该进程所需时间片,wait函数表示等待下一个进程到达所需时间。
FCFS算法优点是简单易懂、公平性好,但其缺点也很明显:无法处理短作业优先问题、平均等待时间长等。
2. 短作业优先(SJF)短作业优先是一种非抢占式的进程调度算法,它根据每个进程的执行时间来进行排序,执行时间短的进程先执行。
如果有多个进程的执行时间相同,则按照到达时间的先后顺序进行调度。
SJF算法代码如下:```void SJF(){int i,j;for(i=0;i<n;i++){for(j=i+1;j<n;j++){if(p[i].need_time>p[j].need_time){swap(p[i],p[j]);}}}for(i=0;i<n;i++){run(p[i].need_time);if(i!=n-1){wait(p[i+1].arrive_time-p[i].arrive_time-p[i].need_time); }}}```其中,swap函数表示交换两个进程的位置。
操作系统进程调度C语言代码#include <stdio.h>#define MAX 20//进程控制块typedef struct PCBchar name[10]; // 进程名int AT; // 到达时间int BT; // 服务时间int Pri; // 优先数int FT; // 完成时间int WT; //等待时间int RT; // 响应时间int position; // 第几号进程int flag; // 用来判断进程是否执行过}PCB;//进程调度void schedule(PCB a[], int n, int alg)int i, j, k, flag, temp;int count = 0;int pri_max = 0;float ATAT = 0.0;float AWT = 0.0;float ART = 0.0;PCBt;//各种算法的调度if (alg == 1)printf("采用先来先服务调度:\n"); //根据到达时间执行for (i = 0; i < n; i++)for (j = i + 1; j < n; j++)if (a[i].AT > a[j].AT)t=a[i];a[i]=a[j];a[j]=t;}//按到达时间依次执行for (i = 0; count != n; i++)for (j = 0; j < n; j++)//查找第一个到达时间小于等于当前时间的进程if (a[j].AT <= i && a[j].flag == 0)//记录运行时间a[j].BT--;//如果运行完成,记录完成时间、等待时间、响应时间if (a[j].BT == 0)a[j].FT=i+1;a[j].WT = a[j].FT - a[j].AT - a[j].Pri;a[j].RT=a[j].WT;a[j].flag = 1;count++;}elsebreak;}}}else if (alg == 2)printf("采用最短服务时间优先(非抢占)调度:\n");for (i = 0; count != n; i++)//找出服务时间最短的进程,并将其放置到最前面for (j = 0; j < n; j++)。
Minix进程实现2.5~2.6概述:本部分内容主要从两个部分介绍进程在Minix中的实现的:第一部分是介绍整个Minix的系统结构的,其中包括了Minix的内部结构以及各种头文件,其主要是对于各个头文件以及进程有关的数据结构的介绍的;第二部分讲的是Minix中进程的实现,其中包括Minix的系统初始化、中断处理、进程间的通信和进程调度。
Minix系统结构介绍:包括Minix内部结构以及各种头文件。
Minix内部四层结构最底层捕获所有的中断和陷入,完成进程调度,并向高层提供一个采用消息进行通信的独立顺序进程模型。
包含完成以下功能的函数:系统初始化、中断、消息传递以及进程调度。
第二层包括了I/O进程,每类设备都有一个I/O进程,我们称之为任务(task)。
只有一个任务,即系统任务与众不同,它不对应于任何I/O设备。
第三层包含向用户进程提供有用服务的进程。
这些服务器进程在低于内核和任务的特权级上运行,不能直接访问I/O端口,也不能访问属于自己段以外的内存。
第四层包含了所有的用户进程——shell、编译器、编辑器以及用户的a.out 程序。
Minix四层结构之间的联系:操作系统主要完成的两件事情:管理资源和通过系统调用方式提供扩展的计算机。
其中,资源管理主要是在内核(第一、二层)完成的,系统调用的解释在第三层。
第三层的各种服务进程被单独的设计成“服务器”,这样可以增加整个系统的可扩展性。
如果要是加入一个新的服务器进程,需要重新编译内核。
Minix源代码的组织源代码从逻辑上分成两个目录:/usr/include/和/usr/src/,记做:include/和/src/。
include/目录包含了许多符合POSIX标准的头文件,它又包含了三个子目录:1.sys/ 包含POSIX头文件2.minix/ 包含操作系统使用的头文件3.ibm/ 包含IBMPC特有定义的头文件。
src/目录包含了三个重要的子目录,其中包括了操作系统的源代码1.kernel/ 第一层和第二层的(进程、消息和驱动程序)2.mm/ 内存管理器代码3.fs/ 文件系统代码公共头文件其中,编译用户程序时可能用到的头文件放在include/目录下,而传统上include/sys/目录放那些编译系统程序和程序所用的头文件。
c语言实现进程调度算法进程调度算法是操作系统中的一个重要组成部分,用于决定在多道程序环境下,选择哪个进程来占用CPU并执行。
C语言是一种通用的编程语言,可以用于实现各种进程调度算法。
这里我将分别介绍三种常见的进程调度算法:先来先服务调度算法(FCFS)、最短作业优先调度算法(SJF)和轮转法调度算法(RR),并给出用C语言实现的示例代码。
首先,我们来看先来先服务调度算法(FCFS)。
此算法根据到达时间的先后顺序,按照先来后到的顺序进行处理。
下面是基于C语言的先来先服务调度算法实现示例代码:```c#include<stdio.h>struct Process};void FCFS(struct Process proc[], int n)for (int i = 1; i < n; i++)}printf("进程号到达时间服务时间完成时间等待时间周转时间\n");for (int i = 0; i < n; i++)}for (int i = 0; i < n; i++)}int maiint n;printf("请输入进程数:");scanf("%d", &n);struct Process proc[n];for (int i = 0; i < n; i++)printf("请输入进程%d的到达时间和服务时间(用空格分隔):", i + 1);}FCFS(proc, n);return 0;```其次,我们来看最短作业优先调度算法(SJF),该算法选择执行时间最短的进程先执行。
下面是基于C语言的最短作业优先调度算法实现示例代码:```c#include<stdio.h>struct Process};void SJF(struct Process proc[], int n)for (int i = 0; i < n; i++)for (int j = 0; j < i; j++)}shortest_job = i;for (int j = i + 1; j < n; j++)shortest_job = j;}}}for (int i = 1; i < n; i++)}printf("进程号到达时间服务时间完成时间等待时间周转时间\n");for (int i = 0; i < n; i++)}for (int i = 0; i < n; i++)}int maiint n;printf("请输入进程数:");scanf("%d", &n);struct Process proc[n];for (int i = 0; i < n; i++)printf("请输入进程%d的到达时间和服务时间(用空格分隔):", i + 1);}SJF(proc, n);return 0;```最后,我们来看轮转法调度算法(RR),该算法分配一个时间片给每个进程,当时间片用完后,将CPU分配给下一个进程。
操作系统五种进程调度算法的代码一、先来先服务(FCFS)调度算法先来先服务(FCFS)调度算法是操作系统处理进程调度时比较常用的算法,它的基本思想是按照进程的提交时间的先后顺序依次调度进程,新提交的进程会在当前运行进程之后排队,下面通过C语言代码来实现先来先服务(FCFS)调度算法:#include <stdio.h>#include <stdlib.h>//定义进程的数据结构struct Processint pid; // 进程标识符int at; // 到达时间int bt; // 执行时间};//进程调度函数void fcfs_schedule(struct Process *processes, int n)int i, j;//根据进程的到达时间排序for(i = 0; i < n; i++)for(j = i+1; j < n; j++)if(processes[i].at > processes[j].at) struct Process temp = processes[i]; processes[i] = processes[j];processes[j] = temp;//获取各个进程执行完毕的时间int ct[n];ct[0] = processes[0].at + processes[0].bt; for(i = 1; i < n; i++)if(ct[i-1] > processes[i].at)ct[i] = ct[i-1] + processes[i].bt;elsect[i] = processes[i].at + processes[i].bt; //计算各个进程的周转时间和带权周转时间int tat[n], wt[n], wt_r[n];for(i = 0; i < n; i++)tat[i] = ct[i] - processes[i].at;wt[i] = tat[i] - processes[i].bt;wt_r[i] = wt[i] / processes[i].bt;printf("P%d:\tAT=%d\tBT=%d\tCT=%d\tTAT=%d\tWT=%d\tWT_R=%f\n", processes[i].pid, processes[i].at, processes[i].bt, ct[i], tat[i], wt[i], wt_r[i]);//主函数int mainstruct Process processes[] ={1,0,3},{2,3,5},{3,4,6},{4,5,2},{5,6,4}};fcfs_schedule(processes, 5);return 0;输出:。
进程调度算法模拟程序设计引言进程调度算法是操作系统中的重要组成部分,它决定了进程在系统中的执行顺序和分配时间片的策略。
为了更好地理解和研究不同的进程调度算法,我们可以设计一个模拟程序来模拟进程的调度过程。
本文将介绍进程调度算法的基本概念和常见的调度算法,并详细讨论如何设计一个进程调度算法模拟程序。
什么是进程调度算法进程调度算法是操作系统中的一种策略,用于决定在多个进程同时请求执行时,系统按照什么样的顺序来选择并分配CPU资源。
进程调度算法的目标是尽可能地提高系统的吞吐量、响应时间和公平性。
常见的进程调度算法先来先服务(FCFS)先来先服务是最简单的进程调度算法,它按照进程到达的先后顺序进行调度。
当一个进程到达系统后,它会被放入就绪队列中,然后按照先后顺序执行。
这种算法的优点是简单易懂,但是存在”饥饿”问题,即长作业会占用CPU资源,导致其他短作业等待时间过长。
短作业优先(SJF)短作业优先算法是根据进程的执行时间来进行调度的。
当一个进程到达系统后,系统会根据其执行时间将其放入适当的位置,执行时间短的进程优先执行。
这种算法可以最大限度地减少平均等待时间,但是对于长作业来说可能会饥饿。
时间片轮转(RR)时间片轮转算法是一种分时调度算法,它将CPU的执行时间划分为多个时间片,每个进程在一个时间片内执行一定的时间,然后切换到下一个进程。
这种算法可以保证所有进程都有机会执行,并且对于响应时间要求较高的任务比较合适。
多级反馈队列(MFQ)多级反馈队列算法是一种综合了FCFS和RR的调度算法。
系统将进程根据优先级划分为多个队列,每个队列都有不同的时间片大小。
当一个进程到达系统后,它被放入第一个队列中,如果在时间片内没有执行完,则被移到下一个队列中。
这种算法可以根据进程的优先级和执行时间动态调整调度策略,提高系统的响应性能。
进程调度算法模拟程序设计程序结构为了设计一个进程调度算法模拟程序,我们需要考虑以下几个方面的内容:1.进程的数据结构:我们可以使用一个进程控制块(PCB)来表示一个进程,PCB包含了进程的状态、优先级、执行时间等信息。
进程调度算法的模拟实现⏹实验目的1.本实验模拟在单处理机情况下的处理机调度问题,加深对进程调度的理解。
2.利用程序设计语言编写算法,模拟实现先到先服务算法FCFS、轮转调度算法RR、最短作业优先算法SJF、优先级调度算法PRIOR、最短剩余时间优先算法SRTF。
3.进行算法评价,计算平均等待时间和平均周转时间。
⏹实验内容及结果1.先来先服务算法2.轮转调度算法3. 优先级调度算法4. 最短时间优先算法5. 最短剩余时间优先算法⏹实验总结在此次模拟过程中,将SRTF单独拿了出来用指针表示,而其余均用数组表示。
⏹完整代码【Srtf.cpp代码如下:】//最短剩余时间优先算法的实现#include<stdio.h>#include<stdlib.h>#include<time.h>typedefstruct{int remain_time;//进程剩余执行时间int arrive_time;//进程到达时间int Tp;//进入就绪队列的时间int Tc;//进入执行队列的时间int To;//进程执行结束的时间int number;//进程编号}Process_Block;//定义进程模块typedefstruct _Queue{Process_Block PB;struct _Queue *next;}_Block,*Process;//定义一个进程模块队列中结点typedefstruct{Process head;//队列头指针Process end;//队列尾指针}Process_Queue;//进程队列Process_Queue PQ;//定义一个全局队列变量int t;//全局时间Process Run_Now;//当前正在运行的进程,作为全局变量void InitQueue(Process_Queue PQ){PQ.head ->next = NULL;PQ.end ->next = PQ.head;}/*初始化队列*/int IsEmpty(Process_Queue PQ){if(PQ.end->next == PQ.head)return 1;//队列空的条件为头指针指向尾指针并且尾指针指向头指针elsereturn 0;}/*判定队列是否为空队列*/void EnQueue(Process_Queue PQ,Process P){Process temp =(Process)malloc(sizeof(_Block));temp = PQ.end;temp->next->next = P;PQ.end->next = P;}/*插入队列操作*/Process DeQueue(Process_Queue PQ){if(IsEmpty(PQ))return NULL;Process temp = PQ.head->next;PQ.head->next= temp ->next;if(PQ.end->next == temp)PQ.end->next = PQ.head;return temp;}/*出列操作*/Process ShortestProcess(Process_Queue PQ){if(IsEmpty(PQ))//如果队列为空,返回{if(!Run_Now)return NULL;elsereturn Run_Now;}Process temp,shortest,prev;int min_time;if(Run_Now)//如果当前有进程正在执行,{shortest = Run_Now;//那么最短进程初始化为当前正在执行的进程,min_time = Run_Now->PB.remain_time;}else//如果当前没有进程执行,{shortest = PQ.head->next;//则最短进程初始化为队列中第一个进程min_time = PQ.head->next->PB.remain_time;}temp = PQ.head;prev = temp;while(temp->next){if(temp->next->PB.remain_time <min_time)//如果当前进程的剩余时间比min_time短,{shortest = temp->next;//则保存当前进程,min_time = shortest->PB.remain_time;prev=temp;//及其前驱}temp=temp->next;}if(shortest == PQ.end->next)//如果最短剩余时间进程是队列中最后一个进程,PQ.end->next = prev;//则需要修改尾指针指向其前驱prev->next = shortest->next;//修改指针将最短剩余时间进程插入到队头return shortest;}/*调度最短剩余时间的进程至队头*/void Run(){Run_Now->PB.remain_time--;//某一时间运行它的剩余时间减return;}/*运行函数*/void Wait(){return ;}int sum(intarray[],int n){int i,sum=0;for(i=0;i<n;i++)sum+=array[i];return sum;}int main(){PQ.head = (Process)malloc(sizeof(_Block));PQ.end = (Process)malloc(sizeof(_Block));Run_Now = (Process)malloc(sizeof(_Block));Run_Now =NULL;InitQueue(PQ);int i,N,Total_Time=0;//Total_Time为所有进程的执行时间之和printf("请输入计算机中的进程数目:\n");scanf("%d",&N);Process *P,temp;P = (Process*)malloc(N*sizeof(Process));int *wt,*circle_t;wt =(int*)malloc(N*sizeof(int));circle_t =(int*)malloc(N*sizeof(int));for(i=0;i<N;i++){P[i] = (Process)malloc(sizeof(_Block));P[i]->PB.number =i+1;P[i]->next =NULL;wt[i] =0;circle_t[i] =0;printf("输入第%d个进程的到达时间及剩余执行时间:\n",i+1);scanf("%d %d",&P[i]->PB.arrive_time,&P[i]->PB.remain_time);}for(i=0;i<N;i++)Total_Time+=P[i]->PB.remain_time;printf("\n进程按顺序运行依次为:\n");i=0;int k=0;for(t=0;;t++){if(Run_Now)//如果当前有进程正在执行{Run();if(t == P[i]->PB.arrive_time)//如果当前时间正好有进程进入{if(P[i]->PB.remain_time < Run_Now->PB.remain_time){temp = P[i];P[i] = Run_Now;Run_Now = temp;//则调度它至运行队列中,Run_Now->PB.Tp=t;Run_Now->PB.Tc=t;wt[Run_Now->PB.number-1]+=Run_Now->PB.Tc-Run_Now->PB.Tp;printf("%d ",Run_Now->PB.number);}EnQueue(PQ,P[i]);//并将当前运行进程重新插入队列中P[i]->PB.Tp=t;k++;i=(i+1)>(N-1)?(N-1):(i+1);}if(Run_Now->PB.remain_time == 0)//如果当前进程运行结束,{Run_Now->PB.To=t;//进程运行结束的时间circle_t[Run_Now->PB.number-1] +=t-Run_Now->PB.arrive_time;free(Run_Now);//则将它所占资源释放掉,Run_Now =NULL;//并修改Run_Now为NULLRun_Now = ShortestProcess(PQ);//从就绪队列中调出最短剩余时间进程至队头,if(!Run_Now)//如果队列为空,转为等待状态{if(IsEmpty(PQ) && k >= N) break;Wait();continue;}else{Run_Now->PB.Tc=t;wt[Run_Now->PB.number-1]+=Run_Now->PB.Tc-Run_Now->PB.Tp;printf("%d ",Run_Now->PB.number);}}}else//如果当前运行进程为空,那么{if(t == P[i]->PB.arrive_time)//如果正好这时有进程入队{k++;EnQueue(PQ,P[i]);Run_Now = DeQueue(PQ);//则直接被调入运行队列中Run_Now->PB.Tp=t;Run_Now->PB.Tc=t;printf("%d ",Run_Now->PB.number);i=(i+1)>(N-1)?(N-1):(i+1);}else{Wait();continue;}}}printf("\n");printf("平均等待时间是:\n%f\n",((float)sum(wt,N))/N);printf("平均周转时间是:\n%f\n",((float)sum(circle_t,N))/N);return 0;}//////////////////////////////////////////////////////【Process.cpp代码如下:】#include<iostream>#include<string>usingnamespace std;class Process{public:string ProcessName; // 进程名字int Time; // 进程需要时间int leval; // 进程优先级int LeftTime; // 进程运行一段时间后还需要的时间};void Copy ( Process proc1, Process proc2); // 把proc2赋值给proc1void Sort( Process pr[], int size) ; // 此排序后按优先级从大到小排列void sort1(Process pr[], int size) ; // 此排序后按需要的cpu时间从小到大排列void Fcfs( Process pr[], int num, int Timepice); // 先来先服务算法void TimeTurn( Process process[], int num, int Timepice); // 时间片轮转算法void Priority( Process process[], int num, int Timepice); // 优先级算法void main(){int a;cout<<endl;cout<<" 选择调度算法:"<<endl;cout<<" 1: FCFS 2: 时间片轮换3: 优先级调度4: 最短作业优先5: 最短剩余时间优先"<<endl; cin>>a;constint Size =30;Process process[Size] ;int num;int TimePice;cout<<" 输入进程个数:"<<endl;cin>>num;cout<<" 输入此进程时间片大小: "<<endl;cin>>TimePice;for( int i=0; i< num; i++){string name;int CpuTime;int Leval;cout<<" 输入第"<< i+1<<" 个进程的名字、cpu时间和优先级:"<<endl;cin>>name;cin>> CpuTime>>Leval;process[i].ProcessName =name;process[i].Time =CpuTime;process[i].leval =Leval;cout<<endl;}for ( int k=0;k<num;k++)process[k].LeftTime=process[k].Time ;//对进程剩余时间初始化cout<<" ( 说明: 在本程序所列进程信息中,优先级一项是指进程运行后的优先级!! )";cout<<endl; cout<<endl;cout<<"进程名字"<<"共需占用CPU时间"<<" 还需要占用时间"<<" 优先级"<<" 状态"<<endl; if(a==1)Fcfs(process,num,TimePice);elseif(a==2)TimeTurn( process, num, TimePice);elseif(a==3){Sort( process, num);Priority( process , num, TimePice);}else// 最短作业算法,先按时间从小到大排序,再调用Fcfs算法即可{sort1(process,num);Fcfs(process,num,TimePice);}}void Copy ( Process proc1, Process proc2){proc1.leval =proc2.leval ;proc1.ProcessName =proc2.ProcessName ;proc1.Time =proc2.Time ;}void Sort( Process pr[], int size) //以进程优先级高低排序{// 直接插入排序for( int i=1;i<size;i++){Process temp;temp = pr[i];int j=i;while(j>0 && temp.leval<pr[j-1].leval){pr[j] = pr[j-1];j--;}pr[j] = temp;} // 直接插入排序后进程按优先级从小到大排列for( int d=size-1;d>size/2;d--){Process temp;temp=pr [d];pr [d] = pr [size-d-1];pr [size-d-1]=temp;} // 此排序后按优先级从大到小排列}/*最短作业优先算法的实现*/void sort1 ( Process pr[], int size) // 以进程时间从低到高排序{// 直接插入排序for( int i=1;i<size;i++){Process temp;temp = pr[i];int j=i;while(j>0 && temp.Time < pr[j-1].Time ){pr[j] = pr[j-1];j--;}pr[j] = temp;}}/*先来先服务算法的实现*/void Fcfs( Process process[], int num, int Timepice){ // process[] 是输入的进程,num是进程的数目,Timepice是时间片大小while(true){if(num==0){cout<<" 所有进程都已经执行完毕!"<<endl;exit(1);}if(process[0].LeftTime==0){cout<<" 进程"<<process[0].ProcessName<< " 已经执行完毕!"<<endl;for (int i=0;i<num;i++)process[i]=process[i+1];num--;}elseif(process[num-1].LeftTime==0){cout<<" 进程"<<process[num-1].ProcessName<< " 已经执行完毕!"<<endl;num--;}else{cout<<endl; //输出正在运行的进程process[0].LeftTime=process[0].LeftTime- Timepice;process[0].leval =process[0].leval-1;cout<<" "<<process[0].ProcessName <<" "<<process[0].Time <<"";cout<<process[0].LeftTime <<" "<<process[0].leval<<" 运行";cout<<endl;for(int s=1;s<num;s++){cout<<" "<<process[s].ProcessName <<" "<<process[s].Time <<"";cout<<process[s].LeftTime <<" "<<process[s].leval<<" 等待"<<endl; ;}} // elsecout<<endl;system(" pause");cout<<endl;} // while}/*时间片轮转调度算法实现*/void TimeTurn( Process process[], int num, int Timepice){while(true){if(num==0){cout<<" 所有进程都已经执行完毕!"<<endl;exit(1);}if(process[0].LeftTime==0){cout<<" 进程"<<process[0].ProcessName<< " 已经执行完毕!"<<endl;for (int i=0;i<num;i++)process[i]=process[i+1];num--;}if( process[num-1].LeftTime ==0 ){cout<<" 进程" << process[num-1].ProcessName <<" 已经执行完毕! "<<endl;num--;}elseif(process[0].LeftTime > 0){cout<<endl; //输出正在运行的进程process[0].LeftTime=process[0].LeftTime- Timepice;process[0].leval =process[0].leval-1;cout<<" "<<process[0].ProcessName <<" "<<process[0].Time <<"";cout<<process[0].LeftTime <<" "<<process[0].leval<<" 运行";cout<<endl;for(int s=1;s<num;s++){cout<<" "<<process[s].ProcessName <<" "<<process[s].Time <<"";cout<<process[s].LeftTime <<" "<<process[s].leval;if(s==1)cout<<" 就绪"<<endl;elsecout<<" 等待"<<endl;}Process temp;temp = process[0];for( int j=0;j<num;j++)process[j] = process[j+1];process[num-1] = temp;} // elsecout<<endl;system(" pause");cout<<endl;} // while}/*优先级调度算法的实现*/void Priority( Process process[], int num, int Timepice){while( true){if(num==0){cout<< "所有进程都已经执行完毕!"<<endl;exit(1);}if(process[0].LeftTime==0){cout<<" 进程" << process[0].ProcessName <<" 已经执行完毕! "<<endl;for( int m=0;m<num;m++)process[m] = process[m+1]; //一个进程执行完毕后从数组中删除num--; // 此时进程数目减少一个}if( num!=1 && process[num-1].LeftTime ==0 ){cout<<" 进程" << process[num-1].ProcessName <<" 已经执行完毕! "<<endl;num--;}if(process[0].LeftTime > 0){cout<<endl; //输出正在运行的进程process[0].LeftTime=process[0].LeftTime- Timepice;process[0].leval =process[0].leval-1;cout<<" "<<process[0].ProcessName <<" "<<process[0].Time <<"";cout<<process[0].LeftTime <<" "<<process[0].leval<<" 运行";cout<<endl; // 输出其他进程for(int s=1;s<num;s++){cout<<" "<<process[s].ProcessName <<" "<<process[s].Time <<" ";cout<<process[s].LeftTime <<" "<<process[s].leval ; if(s==1)cout<<" 就绪"<<endl;elsecout<<" 等待"<<endl;}} // elseSort(process, num);cout<<endl;system(" pause");cout<<endl;} // while}。
计算机操作系统实验指导汤小丹版源代码```python#实验指导:操作系统进程调度算法实现#题目描述:#设计一个操作系统的进程调度算法,使得CPU能够合理地分配给各个进程时间片,并实现算法的模拟。
#要求:#1.设计进程调度算法#2.实现进程控制块#3.实现模拟CPU的运行过程#实验步骤:#1.定义进程控制块#进程控制块(PCB)存储了一个进程的相关信息,包括进程ID、优先级、进程状态等等。
以下是一个简单的PCB类的定义:class PCB:def __init__(self, pid, priority):self.pid = pidself.priority = priorityself.state = 'ready'#2.实现进程调度算法# 进程调度算法决定了CPU如何从就绪队列中选择下一个要执行的进程。
以下是一个简单的调度算法(Round-Robin算法)的实现:def schedule(processes):while True:for process in processes:if process.state == 'ready':print(f"Running process {process.pid}...")process.state = 'running'#3.实现CPU的模拟#在模拟CPU运行过程中,可以将每个进程表示为一个线程,通过调度算法选择要运行的线程,并模拟线程执行的过程。
import threadingclass CPU(threading.Thread):def __init__(self, process):threading.Thread.__init__(self)self.process = processdef run(self):print(f"CPU: Running process {self.process.pid}...")print(f"CPU: Process {self.process.pid} finished.") self.process.state = 'finished'#4.实验结果展示#定义几个进程process1 = PCB(1, 1)process2 = PCB(2, 2)process3 = PCB(3, 3)#将进程放入就绪队列processes = [process1, process2, process3]#调度进程schedule(processes)#模拟CPU运行for process in processes:cpu = CPU(process)cpu.startcpu.join#5.实验总结# 本次实验基于Python语言,实现了一个简单的操作系统进程调度算法模拟。
进程的调度算法调度算法的实质是:根据系统的资源分配策略所规定的资源分配算法。
先介绍⼀下进程调度与作业调度的区别:进程调度是真正让某个就绪状态的进程到处理机上运⾏,⽽作业调度只是使作业具有了竞争处理机的机会。
进程调度(⼜称微观调度、低级调度、短程调度):是按照某种调度算法从就绪状态的进程中选择⼀个进程到处理机上运⾏。
负责进程调度功能的内核程序称为进程调度程序。
作业调度(⼜称⾼级调度、宏观调度、长程调度):是按某种调度算法从后备作业队列中选择作业装⼊内存运⾏;另外当该作业执⾏完毕后,还负责回收系统资源。
完成作业调度功能的程序称为作业调度程序。
下⾯介绍⼏种常见的调度算法:先来先服务(FCFS,first come first served)FCFS调度算法是⼀种最简单的调度算法,该调度算法既可以⽤于作业调度也可以⽤于进程调度。
在作业调度中,算法每次从后备作业队列中选择最先进⼊该队列的⼀个或⼏个作业,将它们调⼊内存,分配必要的资源,创建进程并放⼊就绪队列。
在进程调度中,FCFS调度算法每次从就绪队列中选择最先进⼊该队列的进程,将处理机分配给它,使之投⼊运⾏,直到完成或因某种原因⽽阻塞时才释放处理机。
优点:保证了公平性,规则简单缺点:有利于长进程⽽不利于短进程,有利于CPU 繁忙的进程,⽽不利于I/O 繁忙的进程短作业优先(SJF,Shortest Job First)短作业(进程)优先调度算法是指对短作业(进程)优先调度的算法。
短作业优先(SJF)调度算法是从后备队列中选择⼀个或若⼲个估计运⾏时间最短的作业,将它们调⼊内存运⾏。
⽽短进程优先(SPF)调度算法,则是从就绪队列中选择⼀个估计运⾏时间最短的进程,将处理机分配给它,使之⽴即执⾏,直到完成或发⽣某事件⽽阻塞时,才释放处理机。
优点:相⽐FCFS 算法,该算法可改善平均周转时间和平均带权周转时间,缩短进程的等待时间,提⾼系统的吞吐量。
缺点:该算法对长作业不利,SJF调度算法中长作业的周转时间会增加。
一、实验目的本次实验旨在通过模拟进程调度过程,加深对进程调度算法的理解,并掌握进程调度程序的设计与实现方法。
实验内容主要包括:创建进程、进程调度、进程执行、进程结束等。
二、实验环境操作系统:Linux编程语言:C/C++三、实验内容1. 进程调度算法本实验采用三种进程调度算法:FIFO(先进先出)、时间片轮转法、多级反馈队列调度算法。
2. 进程调度程序设计进程调度程序主要由以下部分组成:(1)进程控制块(PCB)PCB用于描述进程的基本信息,包括进程名、到达时间、需要运行时间、已运行时间、进程状态等。
(2)就绪队列就绪队列用于存储处于就绪状态的进程,按照进程的优先级或到达时间进行排序。
(3)进程调度函数进程调度函数负责从就绪队列中选择一个进程进行执行,并将CPU分配给该进程。
(4)进程执行函数进程执行函数负责模拟进程的执行过程,包括进程的创建、执行、结束等。
四、实验源码```c#include <stdio.h>#include <stdlib.h>#include <time.h>#define MAX_PROCESSES 10typedef struct PCB {int pid;int arrival_time;int need_time;int used_time;int priority;int state; // 0: 等待 1: 运行 2: 完成} PCB;PCB processes[MAX_PROCESSES];int process_count = 0;typedef struct Queue {PCB queue;int front;int rear;int size;} Queue;Queue ready_queue;void init_queue(Queue q) {q->queue = (PCB )malloc(sizeof(PCB) MAX_PROCESSES); q->front = q->rear = 0;q->size = 0;}void enqueue(Queue q, PCB p) {if (q->size == MAX_PROCESSES) {printf("Queue is full.\n");return;}q->queue[q->rear] = p;q->rear = (q->rear + 1) % MAX_PROCESSES; q->size++;}PCB dequeue(Queue q) {if (q->size == 0) {printf("Queue is empty.\n");return NULL;}PCB p = &q->queue[q->front];q->front = (q->front + 1) % MAX_PROCESSES; q->size--;return p;}int is_empty(Queue q) {return q->size == 0;}void print_queue(Queue q) {printf("Queue: ");for (int i = 0; i < q->size; i++) {PCB p = &q->queue[(q->front + i) % MAX_PROCESSES];printf("PID: %d, Arrival Time: %d, Need Time: %d, Used Time: %d, Priority: %d, State: %d\n",p->pid, p->arrival_time, p->need_time, p->used_time, p->priority, p->state);}}void init_processes() {for (int i = 0; i < MAX_PROCESSES; i++) {processes[i].pid = i;processes[i].arrival_time = rand() % 10;processes[i].need_time = rand() % 10 + 1;processes[i].used_time = 0;processes[i].priority = rand() % 3;processes[i].state = 0;}}void schedule() {int time = 0;while (process_count > 0) {for (int i = 0; i < process_count; i++) {PCB p = &processes[i];if (p->arrival_time == time) {enqueue(&ready_queue, p);p->state = 1;}}if (!is_empty(&ready_queue)) {PCB p = dequeue(&ready_queue);p->used_time++;printf("Process %d is running.\n", p->pid);if (p->used_time == p->need_time) {p->state = 2;printf("Process %d is finished.\n", p->pid); }}time++;}}int main() {srand(time(NULL));init_queue(&ready_queue);init_processes();process_count = rand() % MAX_PROCESSES + 1;schedule();print_queue(&ready_queue);return 0;}```五、实验结果与分析1. FIFO调度算法实验结果表明,FIFO调度算法按照进程的到达时间进行调度,可能导致短作业等待时间长,效率较低。
进程调度算法实验报告进程调度算法实验报告一、引言进程调度算法是操作系统中非常重要的一部分,它决定了系统中各个进程的执行顺序和时间分配。
在本次实验中,我们将研究和比较几种常见的进程调度算法,包括先来先服务(FCFS)、最短作业优先(SJF)、轮转法(RR)和优先级调度算法。
二、实验目的本次实验的目的是通过模拟不同的进程调度算法,观察它们在不同情况下的表现,并比较它们的优缺点,以便更好地理解和应用这些算法。
三、实验过程1. 实验环境准备我们使用C语言编写了一个简单的进程调度模拟程序,该程序可以模拟不同的进程调度算法,并输出每个进程的执行顺序和等待时间等信息。
2. 实验步骤(1)先来先服务(FCFS)算法FCFS算法是最简单的一种进程调度算法,它按照进程的到达顺序来执行。
我们通过模拟多个进程的到达时间和执行时间,观察它们的执行顺序和等待时间。
(2)最短作业优先(SJF)算法SJF算法是根据进程的执行时间来进行调度的,执行时间越短的进程优先执行。
我们通过模拟多个进程的执行时间,观察它们的执行顺序和等待时间。
(3)轮转法(RR)算法RR算法是一种时间片轮转的调度算法,每个进程被分配一个时间片,当时间片用完后,进程被挂起,等待下一次调度。
我们通过模拟不同的时间片大小,观察进程的执行顺序和等待时间。
(4)优先级调度算法优先级调度算法是根据进程的优先级来进行调度的,优先级高的进程优先执行。
我们通过模拟不同的进程优先级,观察进程的执行顺序和等待时间。
四、实验结果与分析1. 先来先服务(FCFS)算法当进程的执行时间相差不大时,FCFS算法的等待时间较长,因为后到达的进程需要等待前面的进程执行完毕。
但如果有一个进程的执行时间很长,其他进程的等待时间就会很短。
2. 最短作业优先(SJF)算法SJF算法能够保证最短执行时间的进程先执行,因此平均等待时间较短。
但如果有一个执行时间很长的进程到达,其他进程的等待时间就会变长。
c语言编写的进程调度算法C语言编写的进程调度算法进程调度是操作系统的核心功能之一,它负责按照一定的策略和算法,合理地分配CPU资源给正在运行或即将运行的进程,从而提高操作系统的性能和资源利用率。
在操作系统中,存在多种不同的进程调度算法,本文将以C语言编写进程调度算法为主题,一步一步回答。
第一步:定义进程结构体首先,我们需要定义一个进程的数据结构体,以便在调度算法中使用。
进程结构体包括进程ID、进程优先级、进程状态等信息。
以下是一个简单的进程结构体示例:ctypedef struct {int pid; 进程IDint priority; 进程优先级int state; 进程状态} Process;第二步:初始化进程队列进程队列是存储所有待调度进程的数据结构,可以使用链表或数组来实现。
在初始化进程队列之前,需要先创建一个空的进程队列。
以下是一个简单的初始化进程队列函数:c#define MAX_PROCESSES 100 最大进程数Process processQueue[MAX_PROCESSES]; 进程队列int processCount = 0; 当前进程数void initProcessQueue() {processCount = 0;}第三步:添加进程到队列在调度算法中,需要将新创建或运行的进程添加到进程队列中,这样才能对其进行调度。
以下是一个简单的添加进程到队列的函数:void addProcess(int pid, int priority, int state) {if (processCount >= MAX_PROCESSES) {printf("进程队列已满,无法添加进程!\n");return;}Process newProcess;newProcess.pid = pid;newProcess.priority = priority;newProcess.state = state;processQueue[processCount] = newProcess;processCount++;}第四步:实现进程调度算法进程调度算法决定了操作系统如何决定哪个进程应该被调度并获得CPU 资源。
操作系统实验二进程调度摘要:进程调度是操作系统中重要的功能之一,可以决定进程的优先级和执行顺序。
本实验主要介绍了进程调度的概念、不同的调度算法以及如何实现进程调度。
一、概念介绍进程调度是操作系统中的一项重要功能,用于决定哪个进程能够在处理器上运行。
在操作系统中存在多个进程需要同时运行,而处理器资源有限,因此需要通过进程调度来合理地安排进程的执行顺序,提高系统的效率。
进程调度的目标是使系统的吞吐量最大化、响应时间最短、资源利用率最高等。
常见的调度策略包括先来先服务(FCFS)、最短作业优先(SJF)、时间片轮转、优先级调度等。
二、调度算法介绍1.先来先服务(FCFS)先来先服务(FCFS)是最简单的调度算法,按照进程到达的顺序进行调度,先到达的进程先执行。
FCFS算法不考虑进程的优先级和执行时间,容易导致平均等待时间长。
2.最短作业优先(SJF)最短作业优先(SJF)调度算法按照进程所需的CPU时间进行排序,优先调度所需时间最短的进程。
SJF算法可以减少平均等待时间,但可能会导致长作业等待时间过长。
3.时间片轮转时间片轮转是一种抢占式调度策略,将处理器的使用权分割为若干个时间片,每个进程在一个时间片内运行,如果时间片用完仍未运行完,则将该进程放到队列的末尾,并让下一个进程运行。
时间片轮转算法保证了公平性和响应时间,但可能会导致上下文切换次数过多。
4.优先级调度优先级调度是根据进程的优先级进行调度,优先级高的进程先执行。
优先级可以根据进程类型、实时性等因素确定,不同的操作系统可能有不同的优先级范围和策略。
三、实验步骤1.定义进程结构:定义进程结构体,包含进程ID、进程状态、优先级、执行时间等信息。
2.初始化进程队列:将所有进程按照到达的先后顺序加入到进程队列中。
3.实现调度算法:根据不同的调度算法,实现相应的进程调度算法代码。
可以使用循环遍历进程队列,并根据不同的调度策略决定下一个要执行的进程。
4.执行进程调度:在每个时间片结束后,根据调度算法选取下一个要执行的进程,并更新进程的状态和执行时间。
minix3中的进程调度minix3中的进程调度2010年06月15日星期二12:24最近研究了下minix内核,把进程调度的源码看了下,随便写点。
我是从时钟中断处理函数看是着手的。
在minix中,时钟中断处理函数clock_handler(src/kernel/clock.c)以每秒60次频率被调用。
在clock_handler中更新了当前的进程(proc_ptr)的剩余节拍数(p_ticks_left),如果剩余节拍数小于等于0,就把当前进程指针保存到prev_ptr中再调用lock_notify(HARDWARE,CLOCK)给clock task发送消息。
以上代码来自src/kernel/clock.c中的clock_handler函数clock_task函数先前因为调用receive(ANY,&m)而处于阻塞状态,在clock_handler发送消息后clock_task被激活来处理消息。
在识别正确消息后clock_task调用do_clocktick来做进一步处理。
以上代码来自src/kernel/clock.c中的clock_task函数do_clocktick调用lock_dequeue(prev_ptr)和lock_enqueue(prev_ptr)把时间片用完的进程从就绪队列中移除再插入到就绪队列中的一个合适位置。
以上代码来自src/kernel/clock.c中的do_clocktick函数minix中的就绪进程按16个优先级分别放入16个就绪队列中。
0号队列是优先级最高的,15是最低的。
这16个队列分别由rdy_head指向队列的头和rdy_tail指向队列的尾。
lock_dequeue禁止本地中断后调用dequeue把prev_ptr移除队列。
同样lock_enqueue禁止本地中断后调用enqueue。
在enqueue中先调用sched函数更新进程的优先级和时间片,然后插入到一个适当队列的末尾。
1.Minix3中为每个进程分配的时间片,当进程的时间片用完后,将进行进程调度。
进程的时间片以时钟滴答为单位进行分配。
每次时钟中断,中断处理程序将减少当前进程的时间片。
当时间片减小到0时,进行进程调度,选择一个合适的进程来拥有CPU。
Minix3以每秒钟60次的频率进行时钟中断,即时钟中断处理程序每秒执行60次。
每次执行,减少当前进程的时间片:/* Get number of ticks and update realtime. */ticks = lost_ticks + 1; /* lost_ticks为BIOS中断所花费的时间 */lost_ticks = 0; /* lost_ticks清0 */realtime += ticks; /* 更新时间 */proc_ptr->p_user_time += ticks; /* 更新当前进程的user_time */if (priv(proc_ptr)->s_flags & PREEMPTIBLE) {/* 如果进程可被抢占,则减少时间片 */proc_ptr->p_ticks_left -= ticks;}if (! (priv(proc_ptr)->s_flags & BILLABLE)) {/* 如果当前进程能付费,则修改sys_time及减少时间片 */bill_ptr->p_sys_time += ticks;bill_ptr->p_ticks_left -= ticks;}如果时间片用完,则向clock_task发送通知。
因为该进程的时间片用完,需要重新调度,所以该进程就成为了上一个执行的进程。
if((next_timeout <= realtime)||(proc_ptr->p_ticks_left<= 0)) { /* 如果定时器到期或者进程时间片用完,则进行调度 */prev_ptr = proc_ptr; /* 当前进程成为上一次执行的进程 */lock_notify(HARDWARE, CLOCK); /* send notification */ /* 时间到期时发送通知给clock_task,由该函数进行后续处理 */}2.clock_task为时钟任务的主程序,用一个无限循环等待并处理时钟中断处理程序发来的通知。
没有通知发来时,处于阻塞状态。
while (TRUE) {/* 获取消息 */receive(ANY, &m); /* 无消息时则阻塞 *//* 检查消息类型,只处理时钟中断处理程序发来的消息 */switch (m.m_type) {case HARD_INT:/* 这个消息由时钟中断处理程序(clock_handler)发出 */result = do_clocktick(&m); /* 处理该消息,检查时间片是否到期等 */break; /* result变量没有实际意义 */default: /* illegal request type */kprintf("CLOCK:illegal request %d from %d.\n", m.m_type,m.m_source);}}3.当通过消息检查后,调用do_clocktick函数处理该消息。
首先,检查是否是进程的时间片到期。
如果时间片到期,则重置该进程的时间片,并插入到就绪队列的适当位置。
将进程移出、移入就绪队列,就能完成为进程重新分配时间片和插入适当位置的任务。
if(prev_ptr->p_ticks_left<=0 && priv(prev_ptr)->s_flags & PREEMPTIBLE) { lock_dequeue(prev_ptr); /* 将进程移出队列 */lock_enqueue(prev_ptr); /* 在将进程移入队列 */}lock_dequeue函数将屏蔽中断,然后调用函数dequeue将进程移出就绪队列。
而函数lock_enqueue同样将屏蔽中断,然后调用函数enqueue。
下面详细讨论enqueue 函数。
4.enqueue首先调用函数sched,计算函数的优先级和应分配的时间片。
如果该进程为前一次运行过的进程,即进程连续运行过两次,则降低进程的优先级。
否则该进程可能无限期的占用CPU。
if ( ! time_left) { /* 时间片是否用完 */rp->p_ticks_left = rp->p_quantum_size; /* 分配完整的时间片? */if (prev_ptr == rp) penalty ++; /* 是否要降低进程优先级? */else penalty --; /* 进程都没执行过,则增加进程的优先级 */ prev_ptr = rp; /* 该进程刚运行过 */}接下来,确定进程的优先级。
Minix3中,共有16个优先级队列,最高为0,最低为15。
进程优先级最大为其规定的优先级,最小不能小于IDLE进程的优先级,即最小为14。
if (penalty != 0 && ! iskernelp(rp)) {/* 惩罚值不为0,且该进程不是内核进程 */ rp->p_priority += penalty; /* 根据惩罚值,确定新的优先级 */if (rp->p_priority < rp->p_max_priority) /* 最大为规定的最大优先级*/ rp->p_priority=rp->p_max_priority;else if (rp->p_priority > IDLE_Q-1) /* 不能小于IDLE的优先级 */ rp->p_priority = IDLE_Q-1;}最后,返回进程的优先级。
*queue = rp->p_priority;当进程的时间片未用完,则进程插入队列头部。
用完则插入队列尾部。
时间片未用完的原因有:1.其要求的定时器到期;2.进程请求了I/O操作而被阻塞。
5.进程优先级确定后,就将其插入对应的优先级队列。
这16个队列分别由rdy_head 数组指向每个队列的头和 rdy_tail数组指向每个队列的尾。
if (rdy_head[q] == NIL_PROC) { /* 如果队列为空 */rdy_head[q] = rdy_tail[q] = rp; /* create a new queue */rp->p_nextready = NIL_PROC; /* mark new end */}else if (front) { /* 队列非空,且插入头部。
即时间片未用完 */rp->p_nextready = rdy_head[q]; /* chain head of queue */rdy_head[q] = rp; /* set new queue head */}else { /* 插入队列尾部,即时间片用完 */rdy_tail[q]->p_nextready = rp; /* chain tail of queue */rdy_tail[q] = rp; /* set new queue tail */rp->p_nextready = NIL_PROC; /* mark new end */}6.最后,调用函数pick_proc选择一个优先级最高的进程来拥有CPU。
从16个队列中,从最高的优先级队列开始,选择队头的进程来占有CPU。
for (q=0; q < NR_SCHED_QUEUES; q++) {if ( (rp = rdy_head[q]) != NIL_PROC) {next_ptr = rp; /* run process 'rp' next */if (priv(rp)->s_flags & BILLABLE)bill_ptr = rp; /* bill for system time */return;}}最后,即将要运行的进程由next_ptr指针指示。
7.enqueue函数结束后,将返回到函数lock_enqueue。
接着lock_enqueue将开中断,在中断处理函数运行完之后,内核跳转到_restart处继续执行来完成进程的切换:save:cld ! set direction flag to a known valuepushad ! 保存通用寄存器o16 push ds ! save dso16 push es ! save eso16 push fs ! save fso16 push gs ! save gsmov dx, ss ! ss is kernel data segmentmov ds, dx ! load rest of kernel segmentsmov es, dx ! kernel does not use fs, gsmov eax, esp ! prepare to returnincb (_k_reenter) ! from -1 if not reenteringjnz set_restart1 ! 是否已经是内核堆栈,该情况发生在响应异常时mov esp, k_stktop ! 切换内核堆栈push _restart ! 中断处理完成后的返回地址入栈,即中断完成后转restart进行调度xor ebp, ebp ! for stacktracejmp RETADR-P_STACKBASE(eax) ! 返回到中断处理程序.align 4set_restart1: ! 检查到异常时,才会执行到此处push restart1jmp RETADR-P_STACKBASE(eax)上面的汇编代码是处理中断前保存现场信息的代码,其中在栈中压入了中断完成后的返回地址_restrart。
当中断处理完成后,将转入_restart代码启动一个进程。
_restart:! Restart the current process or the next process if it is set.cmp (_next_ptr), 0 ! 是否有其他进程被调度,pick_proc函数已经选择了一个进程! 所以next_ptr不为0jz 0f ! 如果没有调度其他进程,进继续执行前一个进程mov e ax, (_next_ptr)mov (_proc_ptr), eax ! 调度新进程,proc_ptr = next_ptrmov (_next_ptr), 0 ! next_ptr清00: mov esp, (_proc_ptr) ! will assume P_STACKBASE == 0lldt P_LDT_SEL(esp) ! 装入新进程的局部描述符表(LDT)lea eax, P_STACKTOP(esp) ! 下一次中断的临时堆栈将建立在这地址之后mov (_tss+TSS3_S_SP0), eax ! 将地址保存在TSS中restart1: ! 发生异常时从此处开始执行decb (_k_reenter)o16 pop gso16 pop fso16 pop eso16 pop dspopadadd esp, 4 ! skip return adriretd ! continue process下次中断的临时堆栈将建立在进程结构的stackframe_p结构的后面,硬件将保证临时堆栈不会溢出。