Ucore Lab6 操作系统实验

LAB6实验报告

实验相关知识

(主要从教学ppt、gitbook、学堂在线上了解掌握并根据CSDN查询了解更加详细的信息。同时结合自己的理论课笔记,实际上是对理论知识的复习

1.处理机调度的相关概念

本章主要关于处理机调度,即从就绪队列中挑选下一次执行的进程,也就是给进程CPU资源使用。

CPU调度的两种模式:

  • 抢占式调度。采用非抢占调度,一旦CPU分配给一个进程,那么该进程会一直使用CPU直到进程终止或切换到等待状态
  • 非抢占式调度。系统可以在一个进程仍在使用CPU将其中断并切换调度下一个进程使用

内核执行调度程序的条件:

  1. 当一个进程从运行状态切换到等待状态 running->waiting 例如:I/O请求
  2. 当一个进程从运行状态切换到就绪状态 running->ready 例如:发生中断
  3. 当一个进程从等待状态切换到就绪状态 waiting->ready 例如:I/O请求完成
  4. 当一个进程终止时

需要强调的是,非抢占式调度策略发生的条件为 1 和 4 .抢占式调度策略发生条件为以上均可。

**调度准则:**简单来说,我们希望实现的调度机制能够达到的目标是:CPU使用率尽可能大、吞吐量(单位时间内完成的进程数)尽可能大、周转时间越少越好、等待时间越少越好、响应时间越少越好。

2.调度算法

在介绍具体调度算法之前,需要了解一个事实,那就是进程的CPU使用时间大量地集中于0~8ms这个区间,了解这个事实才可以设计出更好更优秀的算法:
在这里插入图片描述
主要介绍FCFS、SJF、RR、Priority四种调度策略

  • 先到先服务算法 FCFS

    先请求的CPU的进程先分配到CPU。维护一个就绪队列,该就绪队列依据进程进入就绪状态的先后顺序排列。当进程进入等待或结束状态时,就绪队列中的下一个进程获得CPU时间进入运行状态。
    在这里插入图片描述

    • FCFS算法的优点:简单、易于实现

    FCFS算法的缺点:I/O资源和CPU资源利用率较低(CPU密集型进程可能会导致I/O设备长时间闲置),平均等待时间波动较大,可能导致护航现象(长进程在短进程之前执行导致执行时间大大增加)

最短作业优先算法 SJF

预期占用最短CPU时间的进程最先分配到CPU。维护一个就绪队列,该就绪队列依据进程的CPU时间区间由小到大排列,当进程进入等待或结束状态时,就绪队列中的下一个进程获得CPU时间进入运行状态。需要强调的是,一个进程将占用的CPU时间是不可预知的,故这是理论层面算法。该算法有抢占式和非抢占式两种。 非抢占式:每次都给最短的时间,待进程结束后再为当前最短时间分配。抢占式则是一旦有更短的CPU时间的进程,则采取调度策略将其换入运行状态。需要注意的是,抢占式SJF算法可能导致频繁的上下文切换。在这里插入图片描述显然SJF有较好的平均等待时间,实际上有最优的平均等待时间。但存在饥饿现象(由于不断调度短进程导致长进程无法获得CPU时间而一直处于就绪队列不能执行)
时间片轮转算法 RR

**设置一个时间片,执行过程中,如果进程只需要小于时间片的CPU区间,则进程完成后释放CPU。否则定时器中断并产生系统中断,进行上下文切换,将进程加入到就绪队列的尾部。**可以令每个时间片结束时采用FCFS切换到下一个进程。每个进程最长等待时间不超过(n-1)*q时间。

一个设置时间片为20的RR算法示例:在这里插入图片描述

  • **RR算法的时间片设置较为重要,如果设置时间片过大,则接近甚至成为FCFS算法,等待时间将较大;如果设置时间片较小,则产生过多上下文切换,影响系统的吞吐量。**因此,由上面给出的大量进程CPU时间位于8ms以内这个事实,我们可以参考设置RR为8ms左右。

    RR算法的等待时间基本处于FCFS和SJF之间,但具有良好的响应时间。还有需要强调的是RR算法是公平的,交互性较好,等待时间性能较差

  • 优先级调度策略 Priority

    **为每个进程设置一个优先级,优先级高的进程会优先分配到CPU。**实现时可以维护多个队列,每个队列表示一种优先级,优先处理高优先级队列,同优先级采取FCFS即可。优先级调度策略可以采用抢占式和非抢占式两种,实际上SJF可以看作将CPU时间由小到大设为优先级从高到低的策略。可能导致低优先级进程处于饥饿现象,解决办法:老化技术(逐步提升等待时间较长的进程的优先级)

个人认为理解掌握这四种算法核心后基本对其他衍生或者更复杂的算法应该也能很快读懂。

实验过程

本次实验,主要是熟悉ucore的系统调度器框架,以及基于此框架的Round-Robin(RR) 调度算法。然后参考RR调度算法的实现,完成Stride Scheduling调度算法。

练习0:填写已有实验

本实验依赖实验1/2/3/4/5。请把你做的实验2/3/4/5的代码填入本实验中代码中有“LAB1”/“LAB2”/“LAB3”/“LAB4”“LAB5”的注释相应部分。并确保编译通过。注意:为了能够正确执行lab6的测试应用程序,可能需对已完成的实验1/2/3/4/5的代码进行进一步改进。

答:和上个lab一样,这次练习0对前面的代码有一些改进,故在此说明一下。(做练习0必须细心加认真呀)

这次除了将之前的代码copy到框架中之外,还对trap.c和proc.c中部分函数进行了些改动:

trap.c中的trap_dispatch 函数:在时钟产生的地方需要对定时器做初始化,用于调度算法

static void trap_dispatch(struct trapframe *tf)
{
   
   .....
   case IRQ_OFFSET + IRQ_TIMER:	
 		ticks ++;
        assert(current != NULL);
      //更新定时器,并根据参数调用调度算法  
        run_timer_list();
        break;
   .....
}

proc.c中的proc_struct结构体:增加了一些用户调度算法的成员变量

// alloc_proc - alloc a proc_struct and init all fields of proc_struct
static struct proc_struct *
alloc_proc(void) {
   
    struct proc_struct *proc = kmalloc(sizeof(struct proc_struct));
    if (proc != NULL) 
    {
   
        proc->state = PROC_UNINIT;//设置进程为未初始化状态
        proc->pid = -1;          //未初始化的进程id=-1
        proc->runs = 0;          //初始化时间片
        proc->kstack = 0;      //初始化内存栈的地址
        proc->need_resched = 0;   //是否需要调度设为不需要
        proc->parent = NULL;      //置空父节点
        proc->mm = NULL;      //置空虚拟内存
        memset(&(proc->context), 0, sizeof(struct context));//初始化上下文
        proc->tf = NULL;      //中断帧指针设置为空
        proc->cr3 = boot_cr3;      //页目录设为内核页目录表的基址
        proc->flags = 0;      //初始化标志位
        memset(proc->name, 0, PROC_NAME_LEN);//置空进程名
        proc->wait_state = 0;  //初始化进程等待状态  
        proc->cptr = proc->optr = proc->yptr = NULL;//进程相关指针初始化  
        //*cptr-->children | *yptr-->younger | *optr-->older
        proc->rq = NULL; //初始化运行队列为空
//----------------LAB6的补充:---------------------------------        
        list_init(&(proc->run_link)); //初始化运行队列的指针
        proc->time_slice = 0; //初始化时间片
        proc->lab6_run_pool.left = NULL//初始化各类指针为空,包括父进程等待
        proc->lab6_run_pool.right = NULL;
        proc->lab6_run_pool.parent = NULL;  
        proc->lab6_stride = 0; //步数初始化
        proc->lab6_priority = 0; //初始化优先级
    }
    return proc;
}

基于此,即可开始本次实验的主要内容。

练习1: 使用 Round Robin 调度算法(不需要编码)

完成练习0后,建议大家比较一下(可用kdiff3等文件比较软件)个人完成的lab5和练习0完成后的刚修改的lab6之间的区别,分析了解lab6采用RR调度算法后的执行过程。执行make grade,大部分测试用例应该通过。但执行priority.c应该过不去。

请在实验报告中完成:

  • 请理解并分析sched_calss中各个函数指针的用法,并接合Round Robin 调度算法描ucore的调度执行过程
  • 请在实验报告中简要说明如何设计实现”多级反馈队列调度算法“,给出概要设计,鼓励给出详细设计

答:先执行make grade,检验一下练习0是否无误:在这里插入图片描述
因此可知符合预期,只有priority无法通过,与题目描述一致。因此可知练习0是正确的。

接下来分析ucore是如何实现RR算法的:(在"实验相关知识"的"调度算法"内容中由具体的RR算法介绍)

RR算法的核心是设置一个时间片,执行过程中,如果进程只需要小于时间片的CPU区间,则进程完成后释放CPU。否则定时器中断并产生系统中断,进行上下文切换,将进程加入到就绪队列的尾部,然后从其头部取出进程进行调度。

通过数据结构 struct run_queue 来描述完整的 run_queue( 运行队列) 。 它的主要结构如下:(运行队列存储的是当前可以调度的进程, 所以, 只有状态为runnable的进程才能够进入运行队列。 当前正在运行的进程并不会在运行队列中)

struct run_queue 
{
   
    list_entry_t run_list;//运行队列的哨兵结构,看作是队列的头和尾
    unsigned int proc_num;//内部的进程数目 
    <
  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值