抢占式调度

抢占式调度,第1张

概述为什么会发生调度?   因为cpu是有限的,而 *** 作系统上的进程很多,所以 *** 作系统需要平衡各个进程的运行时间 比如说有的进程运行时间已经很长了,已经占用了cpu很长时间了,这个时候 *** 作系统要公平 就会换下一个需要运行的进程。   举个例子   公司只有一个饮水机用来接水,有很多人排队,某个人接完了一杯水,又接下一杯水,一连接了好多杯水,这个时候公司的人事就要过来把这个人赶走 换下一个人接水,然而这个 为什么会发生调度?   因为cpu是有限的,而 *** 作系统上的进程很多,所以 *** 作系统需要平衡各个进程的运行时间 比如说有的进程运行时间已经很长了,已经占用了cpu很长时间了,这个时候 *** 作系统要公平 就会换下一个需要运行的进程。   举个例子   公司只有一个饮水机用来接水,有很多人排队,某个人接完了一杯水,又接下一杯水,一连接了好多杯水,这个时候公司的人事就要过来把这个人赶走 换下一个人接水,然而这个时候老板过来接水了,这个时候下一个人就是老板来接水,而不是后面排队的人,因为什么呢?因为他是老板,就这么强悍   这里面的饮水机就是cpu 人事就是 *** 作系统 等接水的一个个员工就是进程   老板就对应 *** 作系统里的实时进程 普通员工就对应 *** 作系统的普通进程   在 *** 作系统里面实时进程的优先级比普通进程的优先级要高, 所以 *** 作系统在选择下个进程的时候会优先选择实时进程队列里面的进程 除非实时进程里面的进程没有了,这个时候才轮到普通进程     *** 作系统就像人事一样,需要公平的调度和分配资源,当然公司里面有很多老板啊,总经理啊,领导啊 这些人拥有特权,所有分配资源的时候要优先考虑这些老板领导们,这也很正常,谁让人家是老板呢       下面来说说抢占式调度   什么情况下会发生抢占式调度呢? 最常见的现象是你这个进程运行时间太长了,是时候切换到另一个进程了   然而 *** 作系统怎么去统计运行时间呢?   计算机有个时钟的概念,每过一段时间,计算机会通知 *** 作系统,告诉 *** 作系统,又过去了一段时间,你去看看,当前运行的进程运行时间是不是过长了,这个时候 *** 作系统就会去搞这个进程了。   在 *** 作系统中对于每个进程有一个理想运行时间的变量,然后对应还有一个虚拟运行时间和实际运行时间和权重(优先级)。   这三者有什么关系呢?   虚拟运行时间 vruntime += 实际运行时间 delta_exec * NICE_0_LOAD/ 权重(优先级)   通过这个公式可以看出来,给高优先级的进程的虚拟运行时间算少了,给低优先级的进程的虚拟运行时间算多了,但是当 *** 作系统选择下一个进程的时候还是选择虚拟运行时间最少的进程,所以说优先级在这里面就体现出来了。   当某个进程在运行的时候,这个进程的虚拟运行时间会增加,当进程不运行的时候,虚拟时间不增加 其实这里又会涉及到调度器的概念。   这里我们就只说针对普通进程的绝对公平调度策略   这种策略在选取下个进程的时候,是怎么选取的呢? 他是选取当前所有普通进程中运行时间最少的进程,这个应该很好理解吧,因为你在cpu上占用的时间最少,所以为了公平,就要选取你这个进程在cpu上运行。   在 *** 作系统中维护了一个红黑树,红黑树就是一颗平衡二叉树,也就是说红黑树上面挂了好多进程,最左边的进程就是运行时间最少的进程,所有 *** 作系统在,选取下一个进程就会选取这个红黑树上最左侧的进程。   static voID check_preempt_tick(struct cfs_rq *cfs_rq,struct sched_entity *curr) { unsigned long IDeal_runtime,delta_exec; struct sched_entity *se; s64 delta;     IDeal_runtime = sched_slice(cfs_rq,curr); delta_exec = curr->sum_exec_runtime - curr->prev_sum_exec_runtime; if (delta_exec > IDeal_runtime) { resched_curr(rq_of(cfs_rq)); return; } ...... se = __pick_first_entity(cfs_rq); delta = curr->vruntime - se->vruntime; if (delta < 0) return; if (delta > IDeal_runtime) resched_curr(rq_of(cfs_rq)); }   上面代码是linux源码   在 *** 作系统中还有个时间的概念,就是在一个调度周期中,这个进程应该运行的实际时间(IDeal_runtime) sum_exec_runtime指进程总共执行的实际时间,prev_sum_exec_runtime指上次该进程被调度时已经占用的实际时间。   每次在调度一个新的进程时都会把它的se->prev_sum_exec_runtime=se->sum_exec_runtime,所以sum_exec_runtime-prev_sum_exec_runtime 就是这次调度占用实际时间。如果这个时间大于IDeal_runtime,则应该被抢占了。   除了这个条件外,还会通过_pick_first_entity取出红黑树中最小的进程。如果当前进程的vruntime(虚拟运行时间)大于红黑树中最小的进程的vruntime,且差值大于IDeal_time,也应该 被抢占了   当发现这个进程应该被抢占了,不能直接把他踢下去,而是在这个进程上打一个标签TIF_NEED_RESCHED,标示这个进程可以被抢占了   还有一个可能发生抢占的场景,就是当一个休眠的进程被唤醒的时候 这个时候如果这个被唤醒的进程比当前运行的进程的优先级高,则也应该被抢占了,也是在当前运行的进程上打一个标签TIF_NEED_RESCHED   抢占的时机   1.用户态的抢占时机 当该进程进行系统调用从内核态返回到用户态的时候,判断如果该进程有TIF_NEED_RESCHED标签,则进行抢占。   2.内核态的抢占时机 对内核态的执行中,被抢占的时机一般发生在preempt_enable()中。 preempt_disable()关闭抢占 在内核态的执行中,有的 *** 作是不能被中断的,所有在进行这些 *** 作之前,总是先调用preempt_disable()关闭抢占,当再次打开的时候,也就是调用preempt_enable()的时候 就是一次内核态代码被抢占的机会。   在内核态也会遇到中断的情况,当中断返回的时候,返回的仍然是内核态度。这个时候也是一个执行抢占的时机。   大家可以看看这张图理解 了解更多: https://www.toutiao.com/c/user/83293539887/#mid=1633933053814798 总结

以上是内存溢出为你收集整理的抢占式调度全部内容,希望文章能够帮你解决抢占式调度所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/1024705.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存