您当前的位置: 首页 > 

风间琉璃•

暂无认证

  • 4浏览

    0关注

    337博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

CPU调度策略

风间琉璃• 发布时间:2021-09-25 22:36:23 ,浏览量:4

文章目录
  • 前言
  • 一、调度算法
    • 1.FCFS(First Come, First Served)
    • 2.SJF(Shortest Job First)
    • 3.RR(Round Robin)
    • 4.折中方案
  • 二、Schedule()
    • 1.counter(时间片)
    • 2.counter(优先级)
  • 总结

提示:以下是本篇文章正文内容

一、调度算法

设计调度算法的目的:

1.面对用户,目的是让用户满意
2.面对进程:CPU调度的目标是进程满意

进程满意:
尽快结束任务:周转时间(从任务进入到任务结束)短
响应用户操作快:响应时间(从操作发生到响应)短
系统内耗时间少:吞吐量(完成的任务量)

总原则:系统专注于任务执行,又能合理调配任务
1.FCFS(First Come, First Served)

先来先服务算法(FCFS——First Come First Serve):

按照进程就绪的先后顺序使用CPU。 特点:非抢占,公平,实现简单,长进程后面的短进程需要等很长时间,不利于用户体验

三个进程的处理时间分别为12,3,3,分两种进程到达顺序讨论 在这里插入图片描述 优点:调度算法简单

缺点: 1.平均等待时间波动较大,短的进程可能排在长的进程后面得到执行

2.I/O资源和CPU资源利用率较低,CPU密集型进程会导致I/O设备闲置,I/O密集型进程会导致CPU闲置

2.SJF(Shortest Job First)

最短作业优先(SJF——Shortest Job First): 具有最短完成时间的进程优先执行,非抢占

在这里插入图片描述

如果调度结果是 P1,P2,…,Pn,则平均周转时间为: P1 + P2 + P3 + … + Pn = ∑(n + 1 - i) * Pi P1的周转时间是 P1 P2的周转时间是 P1 + P2 …… Pn的周转时间中含有 n*P1 + (n - 1) * P2 + … P1 计算的次数最多,需要把最短的任务放在前边

所以,这种方式平均周转时间最小。

3.RR(Round Robin)

时间片轮转调度算法(Round Robin——RR): 每个进程被分配一个时间片,允许该进程在该时间段运行,如果在时间片结束时该进程还在运行,则剥夺CPU并分配给另一个进程,如果该进程在时间片结RR束前阻塞或结束,则CPU立即进行切换。

特点:公平;有利于交互式计算,响应时间快;由于进程切换,时间片轮转算法要花费较高的开销;对进程表中不同进程的大小差异较大的有利,而对进程都是相同大小的不利。

时间片设计需要避免的两点:

1.时间片太大,等待的时间过长,极限的情况下退化成为FCFS算法

2.时间片太小,反应过于迅速,产生大量的上下文切换,会影响到系统的吞吐量

4.折中方案

我们可以设置优先级,设置前台任务和后台任务,前台任务优先级高,后台任务优先级低,定义前台任务队列和后台任务队列,只有前台任务没有了才调度后台任务

但是,如果一直有前台任务,后台任务一直得不到执行(优先级低的任务一直得不到执行)

所以,任务的优先级要动态调整 一般后台任务 耗时比较长,一旦后台任务转到前台执行,可能耗时很长,一直不释放CPU,前台任务的响应时间又没法保证,前后台任务都要设置时间片,后台任务转到前台,执行一段,要释放CPU,让其他任务执行 在这里插入图片描述

折中方案:短任务优先(减少周转时间)、以 轮转调度为核心,要设置优先级

二、Schedule()

schedule() 的目的是找到下一个任务 next,切换到下一个任务

源码:

// 任务0是一个闲置(idle)任务,只有当其他任务没有运行时才调用它
// 它不能被杀死,也不能睡眠。任务0中的状态信息“state”是从来不用的

void schedule(void)
{
	int i,next,c;
	struct task_struct ** p; // 任务结构体的指针的指针

/* check alarm, wake up any interruptible tasks that have got a signal */
// 检查 alarm(进程的报警定时值),唤醒任何已得到信号的可中断任务

	把p初始化为指向最后一个进程的地址的指针,逆向扫描所有进程,并跳过空指针
	for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
		if (*p) { //*p 指向当前进程的指针
		//jiffies是系统从开机算起的滴答数(每10ms/滴答)
			//判断定时器是否到期,如果到期需要在信号位图中置SIGALARM位,并且将定时器清0
			if ((*p)->alarm && (*p)->alarm signal |= (1signal & ~(_BLOCKABLE & (*p)->blocked)) &&
			(*p)->state==TASK_INTERRUPTIBLE)
				(*p)->state=TASK_RUNNING;   // 置为就绪可以执行状态
		}

/* this is the scheduler proper: */

// 进程的调度
	// 检查就绪的任务,判断下一个运行的任务。
	while (1) {
		c = -1;                 //从最后一个任务开始遍历任务数组
		next = 0;
		i = NR_TASKS;
		p = &task[NR_TASKS];

		//对就绪任务按照时间片进行排序 
		//比较每个就绪状态任务的counter值(任务运行时间的递减滴答计数)
		//哪一个值大,运行的时间还不长,next就指向哪一个任务号
		while (--i) {
			if (!*--p)
				continue;
			if ((*p)->state == TASK_RUNNING && (*p)->counter > c) //counter这里是时间片
			//判断是就绪态,并且 counter>-1,就给c和next赋值,遍历找到最大的counter
				c = (*p)->counter, next = i;
		}

		
		//如果比较得出有counter值不等于0的结果,或者系统中没有一个可运行的任务存在
		//则跳出循环,执行任务切换操作
		if (c) break;

		//如果所有任务的时间片都为0,那么重新计算各个任务的时间片,计算原则是根据优先级进行计算
      	//更新每个任务的counter值,然后再回到开始处比较
		//计算方法:counter = counter/2 + priority
		for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
			if (*p)
				(*p)->counter = ((*p)->counter >> 1) + //counter这里代表优先级
						(*p)->priority;
	}
	//把当前任务指针current指向任务号为next的任务,并切换到该任务中运行
	//若系统中没有其他可运行的任务,则next=0,所以调度去指向空闲任务
	switch_to(next);    // 任务切换,切换到任务号为next的任务,并允许
}
1.counter(时间片)

counter是典型的时间片, 所以是轮转调度, 保证了响应 do_timer 中 counter 减到0,就schedule 在这里插入图片描述

2.counter(优先级)

counter代表的优先级可以动态调整 阻塞的进程再就绪以后优先级高于非阻塞进程 在这里插入图片描述

总结

提示:这里对文章进行总结:

调度函数的核心处理部分:这是根据进程的时间片和优先权调度机制,来选择随后要执行的任务。

它首先循环检查任务数组中的所有任务,根据每个就绪态任务剩余执行时间的值counter,选取该值最大的一个任务,并利用switch _(0)函数切换到该任务。

若所有就绪态任务的该值都等于零,表示此刻所有任务的时间片都已经运行完,于是就根据任务的优先权值pitority,重置每个任务的运行时间片值counter,再重新执行循环检查所有任务的执行时间片值。

关注
打赏
1665385461
查看更多评论
立即登录/注册

微信扫码登录

0.0371s