linux进程调度
Posted 正义飞
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux进程调度相关的知识,希望对你有一定的参考价值。
一,进程调度的作用: 顾名思义,进程调度就是对进程进行调度,即负责选择下一个要运行的进程.通过合理的调度,系统资源才能最大限度地发挥作用,多进程才会有并发执行的效果.二,进度调度的目标和基本工作: 进程调度最终要完成的目标就是为了最大限度的利用处理器时间. 即,只要有可以执行的进程,那么就总会有进程正在执行.当进程数大于处理器个数时,某一时刻总会有一些进程进程不能执行.这些进程等待运行.在这些等待运行的进程中选择一个合适的来执行,是调度程序所需完成的基本工作.
三,调度策略 1, 考虑到进程类型时:I/O消耗型进程 pk 处理器消耗型进程. I/O消耗型进程:指进程大部分时间用来提交I/O请求或者是等待I/O请求. 处理器消耗型进程:与I/O消耗型相反,此类进程把时间大多用在执行代码上. 此时调度策略通常要在两个矛盾的目标中寻找平衡:进程响应时间短(优先I/O消耗型进程)和最大系统利用率(优先处理器消耗型进程). linux为了保证交互式应用,所以对进程的响应做了优化,即更倾向于优先调度I/O消耗型进程. 2, 考虑到进程优先级时: 调度算法中最基本的一类就是基于优先级的调度.调度程序总是选择时间片未用尽而且优先级最高的进程运行. linux实现了一种基于 动态优先级的调度方法.即:一开始,先设置基本的优先级,然后它允许调度程序根据需要加,减优先级. eg:如果一个进程在I/O等待上消耗的时间多于运行时间,则明显属于I/O消耗型进程,那么根据1中的考虑,应该动态提高其优先级. linux提供了两组独立的优先级范围: 1)nice值:范围从-20到+19.默认值是0,值越小,优先级越高.nice值也用来决定分配给进程的时间片的长短. 2)实时优先级:范围为0到99.注意,任何实时进程的优先级都高于普通的进程. 3, 考虑到进程时间片时: 时间片是一个数值,它表明进程在被抢占前所能持续运行的时间.调度策略必须规定一个默认的时间片.时间片过长,则会影响系统的交互性.时间片过短,则会明显增大因进程频繁切换所耗费的时间. 调度程度提供较长的默认时间片给交互式程序.此外,linux调度程序还能根据进程的优先级动态调整分配给它的时间片,从而保证了优先级高的进程,执行的频率高,执行时间长. 当一个进程的时间片耗尽时,则认为进程到期了,此时不能在运行.除非所有进程都耗尽了他们的时间片,此时系统会给所有进程重新计算时间片.
四,linux调度算法 下面为实现调度算法时的一些相关知识点和注意事项. 1,可执行队列(runqueue) 调度程序中最基本的数据结构是可执行队列(runqueue),其结构定义于kernel/sched.c中.可执行队列是给定处理器上的可执行进程的链表, 每个处理器一个. 获得可执行队列: cpu_rq(processor): 获得相关处理器的可执行队列. this_rq(): 获得当前处理器的可执行队列. task_rq(task): 返回给定任务所在的可执行队列. 在对可执行队列进行操作前,应该先锁住它.锁住运行队列的 最常见情况发生在你想锁住的运行队列上恰巧有一个 特定的任务在运行.如下: task_rq_lock(); task_rq_unlock();
struct runqueue *rq; rq = task_rq_lock(task,&flags); /*获得特定任务所对应的可执行队列*/ |
struct prio_array |
struct task_struct *prev, *next; struct list_head *queue; struct prio_array *array; int idx; prev = current; array = rq->active; idx = sched_find_first_bit(array->bitmap); /*找到位图中第一个被设置的位*/ queue = array->queue + idx; /*最高位对应的进程链表*/ next = list_entry(queue->next, struct task_struct, run_list); |
struct task_struct *task; struct runqueue *rq; task = current; rq = this_rq(); if (!--task->time_slice) if (!TASK_INTERACTIVE(task) || EXPIRED_STARVING(rq)) enqueue_task(task, rq->expired); else enqueue_task(task, rq->active); |
/* 'q' is the wait queue we wish to sleep on */ DECLARE_WAITQUEUE(wait, current); add_wait_queue(q, &wait); while (!condition) /* condition is the event that we are waiting for */ set_current_state(TASK_INTERRUPTIBLE); /* or TASK_UNINTERRUPTIBLE */ if (signal_pending(current)) /* handle signal */ schedule(); set_current_state(TASK_RUNNING); remove_wait_queue(q, &wait); |
五,用户抢占与内核抢占 用户抢占时:检查need_resched.如果设置了该位,则重新调度.否则返回执行当前进程. 用户抢占可在以下情况时发生: 1,从系统调用返回用户空间时. 2,从中断处理程序返回用户空间时. 内核抢占时:检查need_resched和preempt_count.如果need_resched被设置,preempt_count为0,则调用schedule().如果need_resched被设置,preempt_count非0,则返回执行当前进程. 内核抢占可能会发生在以下情况时: 1,当中断处理程序正在执行,且返回内核空间之前. 2,当内核代码再一次具有可抢占性的时候. 3,内核中的任务显式调用schedule()时. 4,如果内核中的任务阻塞(这也同样会导致调用schedule()).
以上是关于linux进程调度的主要内容,如果未能解决你的问题,请参考以下文章