第七章 进程调度Word文件下载.docx
- 文档编号:20331766
- 上传时间:2023-01-22
- 格式:DOCX
- 页数:35
- 大小:53.31KB
第七章 进程调度Word文件下载.docx
《第七章 进程调度Word文件下载.docx》由会员分享,可在线阅读,更多相关《第七章 进程调度Word文件下载.docx(35页珍藏版)》请在冰豆网上搜索。
这些进程不必与用户交互,因此,它们经常在后台运行。
因为这样的进程不必被很快地响应,因此,它们常受到调度程序的慢待。
典型的批处理进程是程序设计语言的编译程序、数据库搜索引擎及科学计算。
实时进程(Real-timeprocess)
这些进程有很强的调度需要。
这样的进程决不会被低优先级的进程阻塞,它们应该有一个短的响应时间,更重要的是,响应时间的变化应该很小。
典型的实时程序有视频和音频应用程序、机器人控制程序及从物理传感器上收集数据的程序。
我们刚刚提到的两种分类法在一定程度上相互独立。
例如,一个批处理进程可能是I/O受限型的(如数据库服务器),或是CPU受限型的(如图象着色程序)。
在Linux中,调度算法可以明确地确认所有实时程序的身份,但没有办法区分交互式程序和批处理程序。
Linux2.6调度程序实现了基于进程过去行为的启发式算法,以确定进程应该被当作交互式进程还是批处理进程。
当然,与批处理进程相比,调度程序有偏爱交互进程的倾向。
程序员可以通过表7-1所列的系统调用改变调度优先级。
更详细的内容将在“与调度相关的系统调用”一节中给出。
表7-1与调度相关的系统调用
系统调用说明
nice()改变一个普通进程的静态优先级
getpriority()获得一组普通进程的最大优先级
setpriority()设置一组普通进程的静态优先级
sched_getscheduler()获得一个进程的调度策略
sched_setscheduler()设置一个进程的调度策略和实时优先级
sched_getparam()获得一个进程的实时优先级
sched_setparam()设置一个进程的实时优先级
sched_yield()自愿放弃处理器而不阻塞
sched_get_priority_min()获得一种策略的最小实时优先级
sched_get_priority_max()获得一种策略的最大实时优先级
sched_rr_get_interval()获得时间片轮转策略的时间片值
sched_setaffinity()设置进程的CPU亲合力掩码
sched_getaffinity()获得进程的CPU亲合力掩码
进程的抢占
如第一章所述,Linux的进程是抢占式的。
如果进程进入TASK_RUNNING状态,内核检查它的动态优先级是否大于当前正运行进程的优先级。
如果是,current的执行被中断,并调用调度程序选择另一个进程运行(通常是刚刚变为可运行的进程)。
当然,进程在它的时间片到期时也可以被抢占。
此时,当前进程thread_info结构中的TIF_NEED_RESCHED标志被设置,以便定时中断处理程序终止时调度程序被调用。
例如,让我们考虑一种情况,在这种情况中,只有两个程序—一个文本编辑程序和一个编译程序正在执行。
文本编辑程序是一个交互式程序,因此,它的动态优先级高于编译程序。
不过,因为编辑程序交替于暂停思考与数据输入之间,因此,它经常被挂起;
此外,两次击键之间的平均延迟相对较长。
然而,只要用户一按键,中断就发生,内核唤醒文本编辑进程。
内核也确定编辑进程的动态优先级确实是高于current的优先级(当前正运行的进程,即编译进程),因此,编辑进程的TIF_NEED_RESCHED标志被设置,如此来强迫内核处理完中断时激活调度程序。
调度程序选择编辑进程并执行进程切换;
结果,编辑进程很快恢复执行,并把用户敲的字符回显在屏幕上。
当处理完字符时,文本编辑进程自己挂起等待下一次击键,编译进程恢复执行。
注意被抢占的进程并没有被挂起,因为它还处于TASK_RUNNING状态,只不过不再使用CPU。
此外,记住,Linux2.6内核是抢占式的,这意味着进程无论是处于内核态还是用户态,都可能被抢占,我们曾在第5章“内核抢占”一节深入讨论过这个特征。
一个时间片必须持续多长?
时间片的长短对系统性能是很关键的:
它既不能太长也不能太短。
如果平均时间片太短,由进程切换引起的系统额外开销就变得非常高。
例如,假定进程切换需要5ms,如果时间片也是5ms,那么,CPU至少把50%的时间花费在进程切换上(注2)。
如果平均时间片太长,进程看起来就不再是并发执行。
例如,让我们假定把时间片设置为5秒,那么,每个可运行进程运行大约5秒,但是暂停的时间更长(典型的是5秒乘以可运行进程的个数)。
通常认为长的时间片降低交互式应用程序的响应时间,但这往往是错误的。
正如本章前面“进程的抢占”一节中所描述的那样,交互式进程相对有较高的优先级,因此,不管时间片是多长,它们都会很快地抢占批处理进程。
在一些情况下,一个太长的时间片会降低系统的响应能力。
例如,假定两个用户在各自的shell提示符下分别输入两条命令,其中一条启动一个CPU受限型的进程,而另一条启动一个交互式应用。
两个shell都创建一个新进程,并把用户命令的执行委托给新进程。
此外,又假定这样的新进程最初有相同的优先级(Linux预先并不知道执行进程是批处理的还是交互式的)。
现在,如果调度程序选择CPU受限型的进程执行,那么,另一个进程开始执行前就可能要等待一个时间片。
因此,如果这样的时间片较长,那么,看起来系统就可能对用户的请求反应迟钝。
时间片大小的选择总是一种折衷。
Linux采取单凭经验的方法,即选择尽可能长、同时能保持良好响应时间的一个时间片。
调度算法
早期Linux版本中的调度算法非常简单易懂:
在每次进程切换时,内核扫描可运行进程的链表,计算进程的优先权,然后选择“最佳”进程来运行。
这个算法的主要缺点是选择“最佳”进程所要消耗的时间与可运行的进程数量相关,因此,这个算法的开销太大,在运行数千个进程的高端系统中,要消耗太多的时间。
Linux2.6的调度算法就复杂多了。
通过设计,该算法较好地解决了与可运行进程数量的比例关系,因为它在固定的时间内(与可运行的进程数量无关)选中要运行的进程。
它也很好地处理了与处理器数量的比例关系,因为每个CPU都拥有自己的可运行进程队列。
而且,新算法较好地解决了区分交互式进程和批处理进程的问题。
因此,在高负载的系统中,用户感到在Linux2.6中交互应用的响应速度比早期的Linux版本要快。
调度程序总能成功地找到要执行的进程,事实上,总是至少有一个可运行进程:
即swapper进程,它的PID等于0,而且它只有在CPU不能执行其他进程时才执行。
就象在第三章中提到的,每个多处理器系统的CPU都有它自己的swapper进程,其PID等于0。
每个Linux进程总是按照下面的调度类型被调度:
SCHED_FIFO
先进先出的实时进程。
当调度程序把CPU分配给进程的时候,它把该进程描述符保留在运行队列链表的当前位置。
如果没有其他可运行的高优先权实时进程,进程就继续使用CPU,想用多久就用多久,即使还有其他具有相同优先权的实时进程处于可运行状态。
SCHED_RR
时间片轮转的实时进程。
当调度程序把CPU分配给进程的时候,把该进程的描述符放在运行队列链表的末尾。
这种策略保证对所有具有相同优先权的SCHED_RR实时进程公平地分配CPU时间。
SCHED_NORMAL
普通的分时进程
调度算法根据进程是普通进程还是实时进程而有所不同。
普通进程的调度
每个普通进程都有它自己的静态优先权,调度程序使用静态优先权来估价系统中这个进程与其他普通进程之间调度的程度。
内核用从100(最高优先权)到139(最低优先权)的数表示普通进程的静态优先权。
注意,值越大静态优先权越低。
新进程总是继承其父进程的静态优先权。
不过,通过把某些“让权值“传递给系统调用nice()和setpriority()(参见本章稍后”与调度相关的系统调用),用户可以改变自己拥有的进程的静态优先权。
基本时间片
静态优先权本质上决定了进程的基本时间片,即进程用完了以前的时间片时,系统分配给进程的时间片长度。
静态优先权和基本时间片的关系用下列公式确定:
(1)
如你所见,静态优先权越高,基本时间片就越长。
其结果是,与优先权低的进程相比,通常优先权较高的进程获得更长的CPU时间片。
表7-2说明了普通进程的静态优先权、基本时间片和对应的nice值,与最高静态优先权、缺省静态优先权、最低优先权相对应的nice值。
(表中还列出了交互式的值和睡眠时间极限的值,在本章稍后给予说明)。
表7-2普通进程优先权的典型值
说明
静态优先权
Nice值
交互式的值
睡眠时间的极限值
最高静态优先权
100
-20
800ms
-3
299ms
高静态优先权
110
-10
600ms
-1
499ms
缺省静态优先权
120
100ms
+2
799ms
低静态优先权
130
+10
50ms
+4
999ms
最低静态优先权
139
+19
5ms
+6
1199ms
动态优先权和平均睡眠时间
普通进程除了静态优先权,还有动态优先权,其值的范围是100(最高优先权)到139(最低优先权)。
动态优先权是调度程序在选择新进程来运行的时候使用的数。
它与静态优先权的关系用下面的经验公式表示。
动态优先权=max(100,min(静态优先权-bonus+5,139))
(2)
Bonus是范围从0到10的值,bonus的值小于5表示降低动态优先权以示惩罚,bonus的值大于5表示增加动态优先权以示额外奖赏。
Bonus的值依赖于进程过去的情况,说得更准确一些是与进程的平均睡眠时间相关。
粗略地说讲,平均睡眠时间是进程在睡眠状态所消耗的平均纳秒数。
注意,这绝对不是对过去时间的求平均值的操作。
例如:
在TASK_INTERRUPTIBLE状态与在TASK_UNINTERRUPTIBLE状态的所计算出的平均睡眠时间是不同的。
而且,进程在运行的过程中,平均睡眠时间递减。
最后,平均睡眠时间永远不会大于1秒。
表7-3说明平均睡眠时间和bonus值的关系。
(表中还列出了相应的时间片粒度,这将在稍后讨论)
表7-3平均睡眠时间、bonus值以及时间片粒度
平均睡眠时间Bonus粒度
大于或等于0小于100ms05120
大于或等于100小于200ms12560
大于或等于200小于300ms21280
大于或等于300小于400ms3640
大于或等于400小于500ms4320
大于或等于500小于600ms5160
大于或等于600小于700ms680
大于或等于700小于800ms740
大于或等于800小于900ms820
大于或等于900小于1000ms910
1秒1010
平均睡眠时间也被调度程序用来确定一个给定进程是交互进程还是批处理进程。
更明确地来讲,如果一个进程满足下面的公式,就被看作是交互进程:
动态优先权≤3×
静态优先权/4+28(3)
它相当于下面公式:
bonus-5≥静态优先权/4-28
表达式:
静态优先权/4-28被叫做交互式的;
交互式的一些典型值在表7-2中列出。
应该注意,高优先权进程比低优先权进程更容易成为交互进程。
例如,具有最高静态优先权(100)的进程,当它的bonus值超过2,即睡眠时间超过200ms时,就被看作是交互进程。
相反,具有最低优先权(139)的进程决不会被当作交互进程,因为bonus值总是小于11,相应的需要交互式等于6。
一个具有缺省静态优先权(120)的进程,一但其平均睡眠时间超过700ms就成为交互进程.
活动和过期进程
即使具有较高静态优先权的普通进程获得了较大的CPU时间片,也不应该使静态优先权较低的进程无法运行。
为了避免进程饥饿,当一个进程用完它的时间片时,它应该被还没有用完时间片的低优先权进程取代。
为了实现这种机制,调度程序维持两个不相交的可运行进程的集合。
活动进程
这些进程还没有用完他们的时间片,因此允许他们运行。
过期进程
这些可运行进程已经用完了他们的时间片,并因此被禁止运行,直到所有活动进程都过期。
不过,总体的方案要稍微复杂一些,因为调度程序试图提升交互进程的性能。
用完其时间片的活动批处理进程总是变成过期进程。
用完其时间片的交互进程通常仍然是活动进程:
调度程序重填它的时间片并把它留在活动进程集合中。
但是,如果最老的过期进程已经等待了很长时间,或者过期进程比交互进程的静态优先权高,调度程序就把用完时间片的交互进程移到过期进程集合中。
结果,活动进程集合最终会变为空,过期进程将有机会运行。
实时进程的调度
每个实时进程都与一个实时优先权相关,实时优先权是一个范围从1(最高优先权)到99(最低优先权)的值。
调度程序总是让优先权高的进程运行,换句话说,实时进程运行的过程中,禁止低优先权进程的执行。
与普通进程相反,实时进程总是被当成活动进程(参见上一节)。
用户可以通过系统调用sched_setparam()和sched_setscheduler()改变进程的实时优先权(参见本章稍后“与调度相关的系统调用”一节)。
如果几个可运行的实时进程具有相同的最高优先级,调度程序选择第一个出现在与本地CPU的运行队列相应链表中的进程(参见第3章“TASK_RUNNING进程的链表”)。
只有在下述事件发生时,实时进程才会被另外一个进程取代。
*进程被另外一个具有更高优先权的实时进程抢占。
*-进程执行了阻塞操作并进入睡眠(处于TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE状态)
*进程停止(处于TASK_STOPPED或TASK_TRACED状态)或被杀死(处于EXIT_ZOMBIE或EXIT_DEAD状态)
*-进程通过调用系统调用sched_yield()(参见本章稍后的“与调度相关的系统调用”一节)自动放弃CPU。
*-进程是基于时间片轮转的实时进程(SCHED_RR),而且用完了它的时间片。
系统调用nice()和setpriority(),当用于基于时间片轮转的实时进程时,不改变实时进程的优先权而会改变其基本时间片的长度。
实际上,基于时间片轮转的实时进程的基本时间片的长度与实时进程的优先权无关,而依赖于进程的静态优先权,他们的关系见前面“普通进程的调度“一节中的公式
(1)。
调度程序所使用的数据结构
回忆第三章“标识进程”一节,进程链表链接所有的进程描述符,而运行队列链表链接所有的可运行进程(也就是处于TASK_RUNNING状态的进程)的进程描述符,swapper进程(idle进程)除外。
数据结构runqueue
数据结构runqueue是Linux2.6调度程序最重要的数据结构。
系统中的每个CPU都有它自己的运行队列,所有的runqueue结构存放在runqueues每CPU(per-CPU)变量中(参见第五章“每CPU变量”一节)。
宏this_rq()产生本地CPU运行队列的地址,而宏cpu_rq(n)产生索引为n的CPU的运行队列的地址。
表7-4列出了runqueue数据结构所包括的字段,在下面的章节中我们将对其中的大部分进行讨论。
表7-4runquere结构的字段
类型
名称
spinlock_t
lock
保护进程链表的自旋锁
unsignedlong
nr_running
运行队列链表中可运行进程的数量
Unsignedlong
cpu_load
基于运行队列中进程的平均数量的CPU负载因子
nr_switches
CPU执行进程切换的次数
nr_uninterruptible
先前在运行队列链表中而现在睡眠在TASK_UNINTERRUPTIBLE状态的进程的数量(对所有运行队列来说,这些字段的总数才是有意义的)
expired_timestamp
过期队列中最老的进程被插入队列的时间。
unsignedlonglong
timestamp_last_tick
最近一次定时器中断的时间戳的值
task_t*
curr
当前正在运行进程的进程描述符指针(对本地CPU,它与current相同)
idle
当前CPU(thisCPU)上交换进程的进程描述符指针。
structmm_struct*
prev_mm
在进程切换期间用来存放被替换进程的内存描述符的地址
prio_array_t*
active
指向活动进程链表的指针
expired
指向过期进程链表的指针
prio_array_t[2]
arrays
活动和过期进程的两个集合
int
best_expired_prio
过期进程中静态优先权最高的进程(权值最小)。
atomic_t
nr_iowait
先前在运行队列的链表中而现在正等待磁盘I/O操作结束的进程的数量。
struct
sched_domain*
sd
指向当前CPU的基本调度域(见本章稍后“调度域”)
active_balance
如果要把一些进程从本地运行队列迁移到另外的运行队列(平衡运行队列),就设置这个标志。
push_cpu
未使用
task_t*
migration_thread
迁移内核线程的进程描述符指针。
structlist_head
migration_queue
从运行队列中被删除的进程的链表
runqueue数据结构中最重要的字段是与可运行进程的链表相关的字段字段。
系统中的每个可运行属于且只属于一个运行队列。
只要可运行进程保持在同一个运行队列中,它就只可能在拥有该运行队列的CPU上执行。
但是,正如我们将要看到的,可运行进程会从一个运行队列迁移到另一个运行队列。
运行队列的arrays字段是一个包含两个prio_array_t结构的数组。
每个数据结构都表示一个可运行进程的集合,并包括140个双向链表头(每个链表对应一个可能的进程优先权)、一个优先权位图和一个集合中所包含的进程数量的计数器(参见第三章表3-2)。
图7-1runqueue结构和可运行进程的两个集合
如图7-1所显示的,runqueue结构的active字段指向数组中两个prio_array_t数据结构之一:
对应于包含活动进程的可运行进程的集合。
相反,expired字段指向数组中的另一个prio_array_t数据结构:
对应于包含过期进程的可运行进程的集合。
数组中两个数据结构的作用会发生周期性的变化:
活动进程突然变成过期进程,而过期进程变为活动进程,调度程序简单地交换运行队列的active和expired字段的内容以完成这种变化
进程描述符
每个进程描述符都包括几个与调度相关的字段,他们被列在表7-5中
表7-5与调度程序相关的进程描述符字段
thread_info->
flags
存放TIF_NEED_RESCHED标志,如果必须调用调度程序,则设置该标志(见第四章“从中断和异常返回”一节)
unsignedint
cpu
可运行进程所在运行队列的CPU逻辑号
state
进程的当前状态(见第3章“进程状态”一节)
prio
进程的动态优先权
static_prio
进程的静态优先权
run_list
指向进程所属的运行队列中的下一个和前一个元素。
array
指向包含进程的运行队列的集合:
prio_array_t
sleep_avg
进程的平均睡眠时间
timestamp
进程最近插入运行队列的时间,或涉及本进程的最近一次进程切换的时间。
activated
进程被唤醒时所使用的条件码
policy
进程的调度类型(SCHED_NORMAL,SCHED_RR,或SCHED_FIFO)
cpumask_t
cpus_allowed
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第七章 进程调度 第七 进程 调度