进程的主动调度与抢占式调度

一、主动调度

调用schedule函数进行主动调度,其具体流程比较简单,需要掌握调度类,调度队列,调度实体以及他们和CPU之间的关系,这些知识在上一篇博文《函数堆栈与进程调度基础》中进行了一定简单的介绍。
简言之,当调用schedule函数进行主动调度时,首先会调用通过调度类找到下一个要被调度的进程,然后将当前进程切换状态放入对应调度类的调度队列里面,等待再次被唤醒。而对于被调度的这个队列我们就要对其进行上下文切换

二、进程上下文切换

上下文切换主要干下面两件事,是通过context_switch函数实现的:

  • 切换进程空间,即虚拟内存
  • 切换寄存器和CPU上下文,即保存寄存器等当前进程相关变量
static __always_inline struct rq *
context_switch(struct rq *rq, struct task_struct *prev,
	       struct task_struct *next, struct rq_flags *rf)
{//linux-4.13.16\kernel\sched\core.c
	struct mm_struct *mm, *oldmm;
    ...
	mm = next->mm;
	oldmm = prev->active_mm;
    ...
		switch_mm_irqs_off(oldmm, mm, next);//熟悉吧,对于进程空间的切换
    ...
	/* Here we just switch the register state and the stack. */
	switch_to(prev, next, prev);//寄存器和栈空间的切换,即上面说的切换寄存器和保护上下文
	barrier();//编译器优化指令,保证执行顺序的不变性
	return finish_task_switch(prev);
}

关于进程切换的小总结:

  • 在上面switch_mm_irqs_off进行内存切换时,通过将要切换进程的顶级页表项放在CPU的Cr3寄存器中,实现了用户空间的切换。
  • 内核栈的切换其实还是需要上一讲的知识作为铺垫,因为task_struct里面有一个成员变量就指向进程的内核栈,需要注意的是内核栈是位于内核态的直接映射区的。
  • 至于内核栈的栈顶指针,它会在进程切换时将其值加载到cpu对应的TSS(任务状态段)中,CPU有一个寄存器TR(task register)就是指向这个TSS段的,使用时直接通过这个指针就可以得到了。
  • 而用户态的栈顶指针等一些寄存器变量他会保存在我们上一讲刚刚讲过的内核栈中的pt_regs结构体中,这样当执行用户态时就会恢复进程的上下文情况。。。
    到目前为止,若我们了解计算机组成原理的话就会发现似乎还没有提及指令指针寄存器(IP)的变化,那它是怎样变化的哩?
  • 巧妙的IP寄存器的值变迁,太妙了,这方面极客时间刘超老师的《Linux操作系统调度篇》讲的是真的清楚,他总结的进程调度第一原理——“进程切换时都会调用__schedule的机理”,是顺利理解IP寄存器变迁的良药,超级推荐。
    注意:可以使用ps aux命令查看进程运行时间等基本信息。

三、抢占式调度

主动调度指是某进程主动调用了schedule函数,那么下面是一些发生抢占式调度的时机:

  • 每当系统触发一个时钟中断时就会调用中断处理函数,里面会尝试进行抢占式调度
  • 当一个由于IO而被挂起的进程由于受到IO来了的信号而被唤醒时就会比较与当前正在运行进程的优先级,若被唤醒的IO进程优先级更高就会触发抢占式中断。
    注意:以上两种所谓的抢占式调度只是将当前进程标记为了应该被抢占,但还未真正的被抢占,因为最终只有调用了__shcedule才可以被抢占
    那么什么时候才会调用__shcedule进行真正的抢占式调度哩,具体会分有用户态抢占和内核态抢占时机?
1.用户态抢占时机
  • 进程从系统调用返回用户态时侯是触发调用schedule的一个时机
  • 对用户态进程而言,从中断返回的那个时刻,也是一个被抢占的时机
2.内核态抢占时机
  • 内核定义有一个宏preempt_enable,每当在内核进程进行某些操作之前会先调用该宏判断是否有需要发生抢占的进程(上面对应的发生情况(tick,io线程)会用一个变量做标记),若有的话就会调用shcedule进行调度。
  • 同样和用户态一样,当发生中断返回时也会尝试进行schedule,完成抢占式调度的最后一步。

四、总结

一张非常好看的图片,源:趣谈Linux操作系统:抢占式调度是如何发生的?
调度总结

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 实验目的 调度的实质是操作系统按照某种预定的策略来分配资源。进程调度的目的是分配CPU资源。由于进程调度程序执行的频率很高,因此调度算法的好坏直接影响到操作系统的性能。本实验的目的是编程模拟实现几种常用的进程调度算法,通过对几组进程分别使用不同的调度算法,计算进程的平均周转时间和平均带权周转时间,比较各种算法的性能优劣。 2. 实验原理 [1]. 进程调度算法描述 进程调度算法包括先来先服务调度算法、最短作业时间优先(抢占式和非抢占式)、最高响应比调度算法4种。(每个人必须做FCFS,然后在后面的三种中任选一种,即每个人必须做2种调度算法的模拟。) [2]. 衡量算法性能的参数 计算进程的平均周转时间和平均带权周转时间。 3. 实验内容 (1)编程实现本实验的程序,要求: [1]. 建立进程进程控制块,进程控制块至少包括: a) 进程名称; b) 进程需要执行时间; c) 进入就绪队列时间; d) 进程执行开始时间 e) 进程执行结束时间 [2]. 编程实现调度算法。 [3]. 进程及相关信息的输入。这些信息可以直接从键盘上输入,也可以从文件读取。 [4]. 时间片与时间流逝的模拟。本实验需要对算法的执行计时,程序应该提供计算时间的方法。一种最简单的方法是使用键盘,比如每敲一次空格代表一个时间片的流逝。另一种方法是使用系统时钟。 [5]. 一组进程序列执行完毕,打印出结果信息。程序需要计算出每个进程的开始执行时间、结束时间、周转时间和带权周转时间,并为整个进程序列计算平均周转时间和平均带权周转时间。程序将计算结果按一定的格式显示在计算机屏幕上或输出到文件中。打印出进程调度顺序图。 [6]. 实现数据在磁盘文件上的存取功能。 (2)对下列就绪进程序列分别使用上面的几种算法进行调度,计算每种算法下的平均周转时间和平均带权周转时间。 进程号 到达时间 要求执行时间 0 0 1 1 1 35 2 2 10 3 3 5 4 6 9 5 7 21 6 9 35 7 11 23 8 12 42 9 13 1 10 14 7 11 20 5 12 23 3 13 24 22 14 25 31

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值