码迷,mamicode.com
首页 > 系统相关 > 详细

Linux内核(三)进程调度

时间:2015-06-21 18:35:27      阅读:230      评论:0      收藏:0      [点我收藏+]

标签:

 转载请注明出处:jiq?钦‘s technical Blog 

技术分享


数据结构:

每个处理器维护一个运行队列,主要字段如图所示。

每个运行队列有两个优先级队列,一个活跃的(时间片未完),另一个是过期的(时间片已完)。每个队列都有一个位图,用于快速寻找到当前队列中的最高优先级。

 

Schedule()函数执行步骤如下:

(1)在活动优先级队列的位图数组中找到当前最高优先级;

(2)按照这个优先级数值查找优先级数组,然后在挂在该位置的进程队列(具有相同优先级)上面取下第一个;

(3)如果不是当前正在运行的进程,则做任务切换(调用context_switch()函数)

 

何时调用schedule()函数?

(1)当前进程休眠(阻塞)(主动):将自己标记为休眠状态,把自己从可执行队列移除放入等待队列,然后调用schedule()函数;

(2)当前进程结束(主动):执行do_exit()函数的最后一个步骤,就是调用schedule()函数;

(3)被抢占(被动):这是最为复杂的部分,主要靠一个“全局标志”need_resched完成。

两种情况下这个标志会被设置:

I)当某个进程时间片耗尽时scheduler_tick()函数设置;

II)当一个高优先级任务进入就绪态时try_to_wake_up()函数设置;

标志虽然设置了,但是没有真正启动调度器,什么时候启动呢?

I)用户抢占:

1 执行系统调用(利用中断实现)返回用户空间时检查need_resched标志,如果被设置了就启用调度器:

2 执行中断处理程序返回用户空间时检查need_resched标志,如果被设置了就启用调度器;

II)内核抢占:

注:增加一个标志preempt_count表示当前运行任务(current)所持有锁的数量。

1 中断处理程序返回内核空间时检查如果need_resched标志被设置,并且preempt_count标志值为0,则启用调度器;

2 当前进程执行释放锁的代码会检查preempt_count值若为0(没有持有锁了)并且设置了need_resched标志,则启用调度器;

3 内核显示调用schedule()函数;

注:可以使用preempt_disable()/preempt_enable()函数对禁止和允许内核抢占。

 

Linux进程调度策略:

多任务,抢占式。

基于优先级调度,时间片轮转。

动态优先级,动态时间片。

或者说:

优先级高的先运行,低的后运行,相同优先级的按轮转方式调度。

调度程序总是选择时间片未用尽且优先级最高的进程运行 !!!

 

 

动态优先级如何计算?

每个任务两个优先级:

(1)一个静态优先级。作为初始优先级+作为计算动态优先级基础;

(2)一个动态优先级。其值 = 静态优先级+交互性强度(基于任务休眠时间来计算)

因为我们需要动态提高交互性强的I/O消耗型任务的优先级,I/O消耗型任务执行频率高,执行时间短,休眠时间长,交互性强度高,所以导致动态优先级高。

 

动态时间片如何计算?

优先级越高,时间片越长,nice(优先级数值)越小,执行频率越高!!!

(比如I/O消耗型)

可见优先级和时间片长度成正比!!!

所以只需要将优先级按一定比例缩放,符合时间片数值范围,就是时间片值了。

 

如何保证交互性强的任务(如I/O消耗性)执行频率高?

schedler_tick()函数中:

(1) 当前任务时间片减一操作;

(2)若减为零,判断如果不是交互性强的任务或者过期数组中存在“饥饿进程”,则将当前任务加入过期数组;

否则加入活跃数组(这样就保证了执行频率高些)

也就是说每个时钟周期会检查一次,将交互性强的任务再放回到活跃数组,让其尽快有机会再次得到执行。 

Linux内核(三)进程调度

标签:

原文地址:http://blog.csdn.net/jiyiqinlovexx/article/details/46582763

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!