CPU调度

从就绪队列中挑选下一个占用CPU运行的进程,从多个可用CPU中挑选就绪进程可使用的CPU资源

调度策略

比较调度算法的准则

  • CPU使用率
  • 吞吐量
  • 周转时间
  • 就绪等待时间
  • 响应时间

吞吐量与延迟

  1. 低延迟:喝水的时候想要一打开水龙头水就流出来

  2. 高带宽:给游泳池充水时希望从水龙头里同时流出大量的水,并且不介意是否存在延迟

处理机调度策略的响应时间目标

  1. 减少响应时间
  2. 减少平均响应时间的波动
  3. 增加吞吐量
  4. 减少等待时间

调度算法

先来先服务算法(First Come First Served, FCFS)

依据进程进入就绪状态的先后顺序排列,进程进入等待或结束状态时,就绪队列中的下一个进程占用CPU

但是FCFS的平均等待时间波动较大,I/O资源和CPU资源的利用率较低

短进程优先算法(SPN)

选择就绪队列中执行时间最短进程占用CPU进入运行状态,用历史的执行时间来预估未来的执行时间,短进程优先算法具有最优平均周转时间

但是连续的短进程流会使长进程无法获得CPU资源

最高响应比优先算法(HRRN)

选择就绪队列中响应比R值最高的进程

R=(w+s)/s

    w: 等待时间(waiting time)
s: 执行时间(service time)

时间片轮转算法(RR, Round-Robin)

利用时间片作为分配处理机资源的基本时间单元,时间片结束时,按FCFS算法切换到下一个就绪进程, 每隔(n – 1)个时间片进程执行一个时间片q

但是时间片轮转算法需要选择好时间片的大小,过大过小都会导致效率问题

多级队列调度算法(MQ)

就绪队列被划分成多个独立的子队列,如:前台–RR、后台–FCFS

多级反馈队列算法(MLFQ)

进程可在不同队列间移动的多级队列算法,时间片大小随优先级级别增加而增加,如进程在当前的时间片没有完成,则降到下一个优先级

公平共享调度(FSS, Fair Share Scheduling)

FSS控制用户对系统资源的访问,一些用户组比其他用户组更重要,保证不重要的组无法垄断资源,未使用的资源按比例分配,没有达到资源使用率目标的组获得更高的优先级

代码实现

这个实验其实有两个,一个是实现Round Robin,一个是Stride Scheduling,两个都非常简单。

Round Robin调度算法的调度思想是让所有 runnable 态的进程分时轮流使用 CPU 时间。Round Robin 调度器维护当前 runnable进程的有序运行队列。当前进程的时间片用完之后,调度器将当前进程放置到运行队列的尾部,再从其头部取出进程进行调度。

Stride Scheduling

具体看一下Stride Scheduling

1、为每个runnable的进程设置一个当前状态stride,表示该进程当前的调度权。另外定义其对应的pass值,表示对应进程在调度后,stride 需要进行的累加值。

2、每次需要调度时,从当前 runnable 态的进程中选择 stride最小的进程调度。对于获得调度的进程P,将对应的stride加上其对应的步长pass(只与进程的优先权有关系)。

3、在一段固定的时间之后,回到步骤2,重新调度当前stride最小的进程

static void
stride_init(struct run_queue *rq) {
/* LAB6: YOUR CODE */
list_init(&(rq->run_list));
rq->lab6_run_pool = NULL;
rq->proc_num = 0;
}

首先是队列初始化函数

static void
stride_enqueue(struct run_queue *rq, struct proc_struct *proc) {
/* LAB6: YOUR CODE */
#if USE_SKEW_HEAP
rq->lab6_run_pool = skew_heap_insert(rq->lab6_run_pool, &(proc->lab6_run_pool), proc_stride_comp_f);
#else
assert(list_empty(&(proc->run_link)));
list_add_before(&(rq->run_list), &(proc->run_link));
#endif
if (proc->time_slice == 0 || proc->time_slice > rq->max_time_slice) {
proc->time_slice = rq->max_time_slice;
}
proc->rq = rq;
rq->proc_num ++;
}

然后是入队函数stride_enqueue,根据之前对该调度算法的分析,这里函数主要是初始化刚进入运行队列的进程 proc 的stride属性,然后比较队头元素与当前进程的步数大小,选择步数最小的运行,即将其插入放入运行队列中去,这里并未放置在队列头部。最后初始化时间片,然后将运行队列进程数目加一。

static void
stride_enqueue(struct run_queue *rq, struct proc_struct *proc) {
/* LAB6: YOUR CODE */
#if USE_SKEW_HEAP
rq->lab6_run_pool = skew_heap_insert(rq->lab6_run_pool, &(proc->lab6_run_pool), proc_stride_comp_f);
#else
assert(list_empty(&(proc->run_link)));
list_add_before(&(rq->run_list), &(proc->run_link));
#endif
if (proc->time_slice == 0 || proc->time_slice > rq->max_time_slice) {
proc->time_slice = rq->max_time_slice;
}
proc->rq = rq;
rq->proc_num ++;
}
static void
stride_dequeue(struct run_queue *rq, struct proc_struct *proc) {
/* LAB6: YOUR CODE */
#if USE_SKEW_HEAP
rq->lab6_run_pool = skew_heap_remove(rq->lab6_run_pool, &(proc->lab6_run_pool), proc_stride_comp_f); //从优先队列中移除
#else
assert(!list_empty(&(proc->run_link)) && proc->rq == rq);
list_del_init(&(proc->run_link));
#endif
rq->proc_num --;
}
static struct proc_struct *
stride_pick_next(struct run_queue *rq) {
/* LAB6: YOUR CODE */
#if USE_SKEW_HEAP
if (rq->lab6_run_pool == NULL) return NULL;
struct proc_struct *p = le2proc(rq->lab6_run_pool, lab6_run_pool);
#else
list_entry_t *le = list_next(&(rq->run_list)); if (le == &rq->run_list)
return NULL; struct proc_struct *p = le2proc(le, run_link);
le = list_next(le);
while (le != &rq->run_list)
{
struct proc_struct *q = le2proc(le, run_link);
if ((int32_t)(p->lab6_stride - q->lab6_stride) > 0)
p = q;
le = list_next(le);
}
#endif
//更新对应进程的stride值
if (p->lab6_priority == 0)
p->lab6_stride += BIG_STRIDE;
else p->lab6_stride += BIG_STRIDE / p->lab6_priority;
return p;
}

接下来就是进程的调度函数stride_pick_next,观察代码,它的核心是先扫描整个运行队列,返回其中stride值最小的对应进程,然后更新对应进程的stride值,将步长设置为优先级的倒数,如果为0则设置为最大的步长。

static void
stride_proc_tick(struct run_queue *rq, struct proc_struct *proc) {
/* LAB6: YOUR CODE */
if (proc->time_slice > 0)
{
proc->time_slice --;
}
if (proc->time_slice == 0)
{
proc->need_resched = 1;
}
}

最后是时间片函数stride_proc_tick,主要工作是检测当前进程是否已用完分配的时间片。

相对于这两个算法我觉得更重要的是明白进程的调度时机

  1. 时钟中断处理函数检测到时间片到期了
  2. 发生阻塞或者睡眠等情况

Lab6:进程的调度的更多相关文章

  1. 实验二 用C语言表示进程的调度

    实验二 一. 实验目的 通过模拟进程的调度,进一步了解进程的调度的具体过程. 二. 实验内容和要求 1.进程PCB的结构体定义 2.定义队列 3.输入进程序列 4.排序(按到位时间) 5.输出进程运行 ...

  2. RHCA学习笔记:RH442-Unit8进程与调度

      UNIT 8  Processes and the Scheduler 进程与调度 学习目标 A. CPU cache 与Service time之间的关系 B. 分析应用程序使用CPU cach ...

  3. Linux进程组调度机制分析【转】

    转自:http://oenhan.com/task-group-sched 又碰到一个神奇的进程调度问题,在系统重启过程中,发现系统挂住了,过了30s后才重新复位,真正系统复位的原因是硬件看门狗重启的 ...

  4. 《linux内核设计与实现》阅读笔记-进程与调度

      一.进程 process: executing program code(text section) data section containing global variables open f ...

  5. 分析Linux内核中进程的调度(时间片轮转)-《Linux内核分析》Week2作业

    1.环境的搭建: 这个可以参考孟宁老师的github:mykernel,这里不再进行赘述.主要是就是下载Linux3.9的代码,然后安装孟宁老师编写的patch,最后进行编译. 2.代码的解读 课上的 ...

  6. Linux进程核心调度器之主调度器schedule--Linux进程的管理与调度(十九)

    主调度器 在内核中的许多地方, 如果要将CPU分配给与当前活动进程不同的另一个进程, 都会直接调用主调度器函数schedule, 从系统调用返回后, 内核也会检查当前进程是否设置了重调度标志TLF_N ...

  7. Golang进程权限调度包runtime三大函数Gosched、Goexit、GOMAXPROCS

    转自:https://www.cnblogs.com/wt645631686/p/9656046.html runtime.Gosched(),用于让出CPU时间片,让出当前goroutine的执行权 ...

  8. linux进程、调度、线程、进程上下文等几点理解

    1.信号来自进程或内核 2.线程共享进程的代码空间和数据空间(全局变量或静态变量),文件描述符,信号,以及malloc分配的内存,每个线程拥有独立的栈空间和程序计数器,在创建线程时,调用pthread ...

  9. 《Linux内核设计与实现》读书笔记(四)- 进程的调度

    主要内容: 什么是调度 调度实现原理 Linux上调度实现的方法 调度相关的系统调用 1. 什么是调度 现在的操作系统都是多任务的,为了能让更多的任务能同时在系统上更好的运行,需要一个管理程序来管理计 ...

随机推荐

  1. HTTP 结构详解

    转至 :https://blog.csdn.net/u010256388/article/details/68491509?utm_source=copy   引用 学习Web开发不好好学习HTTP报 ...

  2. unity 基于scrollRect实现翻页显示

    unity 基于scrollRect实现翻页显示,并定为到某一页,而不是某一页的中间方法(第二个脚本采用实际位置计算,并在update里实现平滑过渡): 组场景时,经常需要获取鼠标(或者点击)开始结束 ...

  3. webpack中如何使用图标字体

    1.webpack安装相关依赖 $ npm install font-awesome-webpack less less-loader css-loader style-loader file-loa ...

  4. fenby C语言 p7

    /*小小加法计算器*/=函数功能说明;(多行) //=注释:(一行) P8 比较 #include <stdio.h>int main(){ int a=10,b=20; if(a< ...

  5. 二:Mysql库相关操作

    1:系统数据库 information_schema: 虚拟库,不占用磁盘空间,存储的是数据库启动后的一些参数,如用户表信息.列信息.权限信息.字符信息等.performance_schema: My ...

  6. Flask:Flask-script插件

    Flask-Script插件扩展提供向Flask插入外部脚本的功能,包括一个开发用的服务器,一个定制的python shell,设置数据库的脚本,cronjobs,及其它运行在web应用之外的命令行任 ...

  7. FTP上传、下载文件Demo

    前言:最近在做一个app,负责写后台接口,客户那边给了一个FTP的账号密码过来,服务器上面放了一堆的PDF文件,让我们这边自己从上面拿,项目是spriongboot的,做个记录供以后参考. 一.app ...

  8. CVE-2019-0708复现之旅

    CVE-2019-0708 0x00 前言: CVE-2019-0708漏洞已经出来三四个月了对应的poc也出现了很久 ,exp 还是没动静前段时间出了个蓝屏伪exp 不过肯定那些大厂手里早已经了有了 ...

  9. MIT线性代数:7.主变量,特解,求解AX=0

  10. TCP/IP协议第一卷第三章 IP首部分析

    IP介绍 IP是TCP/IP协议族中最为核心的协议.所有的TCP.UDP.ICMP.IGMP数据都以IP数据报格式传输. IP提供不可靠.无连接的数据报传送服务. 不可靠(unreliable)它不能 ...