深入理解Linux内核(学习笔记)_第七章进程调度

     Linux与任何分时系统一样,通过一个进程到另一个进程的快速切换,达到表明上看来多个进程同时执行的神奇效果。

一.调度策略

     传统的Unix操作系统的调度算法必须实现几个相互冲突的目标:进程响应时间尽可能快,后台作业的吞吐量尽可能高,尽可能避免进程的饥饿现象,低优先级和高优先级的需要尽可能调和等等。决定什么时候以什怎样的方式选择一个新的进程运行的这组规则就是所谓的调度策略。Linux的调度基于分时的技术:多个进程以“时间多路复用”方式运行,因为CPU的时间被分成“片”,给每个可运行进程分配一片。进程调度也是根据进程的优先级对它们进行分类。有时用复杂的算法求出进程当前的优先级,但最后的结果是相同的:每个进程都与一个值相关联,这个值表示把进程如何适当地分配给CPU。传统上把进程分类为“I/O受限”或“CPU受限”。另一种分类法把进程区分为三类:交互式进程、批处理进程、实时进程。

  • 进程抢占:Linux的进程是抢占式的,如果进程进入Task_Running状态,内核检查它的动态优先级是否大于当前正运行进程的优先级。
  • 一个时间片必须持续多长:时间片的长短对系统性能是很关键的,它既不能太长也不能太短。如果时间片太短,由进程切换引起的系统额外开销就变得非常高,如果平均时间片太长,进程看起来就不再是并发执行的,会降低系统的响应能力。对时间片大小的选择始终是一种折中,Linux采取单凭经验的方法,即选择尽可能长、同时能保持良好响应的一个时间片。

二.调度算法

     早期的调度算法:在每次进程切换时,内核扫描可运行进程的链表,计算进程的优先级,然后选择“最佳”进程来运行。这个算法的主要缺点是选择“最佳”进程所要消耗的时间与可运行的进程数量相关,这个算法开销太大,在运行数千个进程的高端系统中要消耗太多的时间。Linux 2.6的调度算法就复杂多了,在高负载的系统中,响应速度较早期要快。调度算法根据进程是普通进程还是实时进程而有很大不同。

  • 普通进程调度:每个普通进程都有它自己的静态优先级,调度程序使用静态优先级来估价系统中这个进程与其他普通进程之间调度的程度。时间片:静态优先级本质上决定了进程的基本时间片,即进程用完了以前的时间片时,系统分配给进程的时间片长度。动态优先级和平均睡眠时间:动态优先级是调度程序在选择新进程来运行的时候使用的数。它与静态优先级的关系用下面的经验公式表示:动态优先级=max(100,min(静态优先级-bonus+5,139))bonus是范围从0~10的值。活动和过期进程:即使具有较高静态优先级的普通进程获得了较大的CPU时间片,也不应该使静态优先级较低的进程无法运行,为了实现这种机制,调度程序维持两个不想交的可运行进程(获得进程、过期进程)的集合。
  • 实时进程的调度:每个实时进程都与一个实时优先级相关,实时优先级是一个范围从1~99的值。只有在下述事件之一发生时,实时进程才会被另一个进程取代:(1)进程被另一个具有更高实时优先级的实时进程抢占;(2)进程执行了阻塞操作并进入睡眠;(3)进程停止或被杀死;(4)进程通过调用系统调用sched_yield()自愿放弃CPU;(5)进程是基于时间片轮转的实时进程(SCHED_RR),而且用完了它的时间片。

三.调度程序所使用的数据结构

  •  数据结构runqueue:系统中的每个CPU都有它自己的运行队列,所有的runqueue结构存放在runqueue每CPU变量中,宏this_rq()产生本地CPU运行队列的地址,而宏cpu_rq(n)产生索引为n的CPU的运行队列的地址。
  • 进程描述符:每个进程描述符都包括几个与调度相关的字段。

四.调度程序所使用的函数

  • scheduler_tick():维持当前最新的time_slice计数器
  • try_to_wake_up():唤醒睡眠进程
  • recalc_task_prio():更新进程的动态优先级
  • schedule():选择要被执行的新进程
  • load_balance():维持多处理器系统中运行队列的平衡

五.多处理器系统中运行队列的平衡

    特别关注下面三种不同类型的多处理器机器:标准的多处理器体系结构、超线程、NUMA。

  • 调度域:调度域实际上是一个CPU集合,它们的工作量应当由内核保存平衡。一般来说,调度域采取分层的组织形式:最上层的调度域包括多个子调度域,每个子调度域包括一个CPU子集。每个调度域被依次划分成一个或多个组,每个组代表调度域的一个CPU子集,工作量的平衡总是在调度域的组之间来完成。
  • rebalance_tick()函数:为了保持系统中运行队列的平衡,每次经过一次时钟节拍,scheduler_tick()就调用rebalance_tick()函数。它接受的参数有:本地CPU的下标this_cpu、本地运行队列的地址this_rq以及一个标志idle。
  • load_balance()函数:检查是否调度域处于严重的不平衡状态。更确切地说,它检查是否可以通过把最繁忙的组中的一些进程迁移到本地CPU的运行队列来减轻不平衡的状况。
  • move_tasks()函数:把进程从源程序队列迁移到本地运行队列。

六.与调度相关的系统调用

  • nice()系统调用:允许进程改变它们的基本优先级。
  • getpriority和setpriority系统调用:作用于给定组中所有进程的基本优先级。
  • sched_getaffinity()和sched_setaffinity()系统调用:分别返回和设置CPU进程亲和力掩码,也就允许执行进程的CPU的位掩码。
  • 与实时进程先关的系统调用:sched_getscheduler()和sched_setscheduler()系统调用、sched_getparam()和sched_setparam()系统调用、sched_yield()系统调用、sched_get_priority_min()和sched_get_priority_max()系统调用、sched_rr_get_interval()系统调用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值