当前位置: 首页 > Linux

Linux进程调度

时间:2023-04-07 01:16:02 Linux

processstate进程调度就是将进程从一种状态切换到另一种状态。Linux中进程的主要状态如下,值状态的缩写含义0TASK_RUNNINGR正在运行或可以运行1TASK_INTERRUPTIBLES可中断睡眠2TASK_UNINTERRUPTIBLED不可中断睡眠4__TASK_STOPPEDT停止状态,当进程收到SIGSTOP等信号信息时8__TASK_TRACEDt跟踪状态,进程被调试程序挂起,例如使用ptrace()调试16EXIT_ZOMBIEZ僵尸状态。当进程结束时,调用do_exit()进入僵尸状态32EXIT_DEADX死亡状态。父进程使用waitpid()或wait4()回收死掉的子进程后,状态由EXIT_ZOMBIE变为EXIT_DEAD图中大致展示了进程状态的切换,可以更直观的了解各种进程状态。上图中需要补充的是,进程在“占用CPU执行”时应该处于TASK_RUNNING状态。EXIT_ZOMBIE状态应该很短。父进程需要使用wait系统调用来回收子进程。回收后,进程状态会变为EXIT_DEAD。如果父进程不回收,子进程就会变成僵尸进程。__TASK_TRACED状态只会在使用调试器时出现。例如,使用gdb设置断点,当进程暂停在断点处时,就处于跟踪状态。调度器系统中有很多进程,内核负责保持所有进程运行,让重要的进程运行更多。这就需要一种机制来管理所有进程。在内核中安排进程执行的模块称为调度程序。调度程序选择一个处于就绪状态的进程,并为其分配一个CPU时间片来运行。当一个进程运行的时间片耗尽时,调度器会将其转换为就绪状态,并将其插入到准备执行的进程队列中。一个进程让出CPU进入休眠或挂起后,如果被唤醒,调度器也会将其插入到就绪队列中。因此,调度器将解决两个核心问题:分配合适的时间片和合理安排进程的执行顺序。最原始的调度策略就是按照优先级来安排进程,等到一个进程运行完再运行优先级低的进程,但这种策略根本无法发挥多任务系统的优势。因此,操作系统调度程序随着时间的推移已经发展了很多次。Linux2.4内核引入了O(n)调度器,它将时间划分为大量微小的时间片(Epoch)。在每个时间片的开始,调度程序检查所有处于就绪状态的进程。调度器计算每个进程的优先级,选择优先级最高的进程执行。一旦被调度器切换到执行状态,进程就可以不间断地用完这个时间片。如果进程还没有用完它的时间片,则该时间片的剩余时间被添加到下一个时间片。O(n)调度程序在使用每个时间片之前检查所有就绪进程的优先级。这个检查时间与进程中的进程数n成正比,这就是调度器复杂度为O(n)的原因。当计算机中有大量进程在运行时,这个调度器的性能会大大降低。为了解决O(n)调度器的性能问题,从Linux2.6内核开始就发明并使用了O(1)调度器。O(1)调度器的创新之处在于它会按照优先级对进程进行排列,并将它们放入特定的数据结构中。在选择下一个要执行的进程时,调度器可以直接选择优先级最高的进程,而无需遍历进程。O(1)调度程序将使用两个队列来存储进程。一个队列称为活动队列,用于存放那些等待分配时间片的进程。另一个队列叫做过期队列,用来存放已经享受过时间片的进程。O(1)调度程序从活动队列中的进程中取出一个时间片。当进程用完时间片时,会被转移到过期队列中。当active队列中的所有进程都执行完毕后,调度器会把active队列和expired队列倒序,以同样的方式继续执行这些进程。从Linux2.6.23版本开始,完全公平调度器(CFS,CompletelyFairScheduler)取代了O(1)调度器。CFS调度程序不会对进程执行任何形式的估计或猜测。这与区分交互进程和非交互进程的O(1)方法完全不同。CFS调度器增加了虚拟运行时的概念。进程每在CPU中执行一段时间,其虚拟运行时记录就会递增。每次选择一个进程执行时,不是选择具有最高优先级的进程,而是选择具有最少虚拟运行时间的进程。完全公平调度器将O(1)调度器的140个队列替换为称为红黑树的数据结构。红黑树可以高效地找到最小的虚拟运行进程。CFS调度程序根据进程的优先级计算时间片因子。同样加上250纳秒的虚拟运行时间,低优先级的进程实际上可能只得到200纳秒,而高优先级的进程实际上可能得??到300纳秒。这样,优先级高的进程可以获得更多的计算资源。进程优先级进程优先级影响调度器的时间片分配和进程执行顺序。Linux根据进程的特点,按照优先级将进程分为两类:实时进程和普通进程。实时进程:需要尽快执行的高优先级进程。不能被普通进程阻塞,比如视频播放,各种监控系统。NormalProcess:优先级低,执行时间长的进程。示例包括文本编译器、文档的批处理和图形渲染。实时进程不是真正实时的,也需要进程调度,但会先于正常进程运行。进程的优先级是一个0到139的整数,数字越小,优先级越高。其中,优先级0~99为实时进程保留,100~139为普通进程保留。普通进程的默认优先级是120,可以通过nice命令修改进程的默认优先级。以下命令表示将默认优先级更改为(120-20)。$nice-n-20./app普通进程的默认优先级称为静态优先级,进程在运行时实际上使用的是动态优先级。调度器通过增加或减少进程静态优先级的值来奖励消耗IO的进程或惩罚消耗CPU的进程。调整后的优先级称为动态优先级。动态优先级的计算公式如下。Dynamicpriority=max(100,min(staticpriority–bonus+5,139))bonus是0到10之间的一个值,小于5表示降低动态优先级作为惩罚,大于5表示增加动态优先级作为奖励。调度策略在Linux系统中,实时进程和普通进程采用不同的调度策略。实时进程采用实时调度策略,分为三种:SCHED_FIFO、SCHED_RR、SCHED_DEADLINE。SCHED_FIFO:先进先出的实时进程。当调度程序为进程分配CPU时,它会将进程描述符保留在运行队列列表中的当前位置。如果没有其他更高优先级的实时进程可运行,则该进程会继续使用CPU,只要它愿意,即使有其他具有相同优先级的可运行实时进程也是如此。由RT调度器实现。SCHED_RR:时间片轮转实时进程。当调度程序为进程分配CPU时,它会将进程的描述符放在运行列表的末尾。该策略保证将CPU时间公平分配给具有相同时间优先级的所有SCHED_RR实时进程。由RT调度器实现。SCHED_DEADLINE:新支持的实时进程调度策略,适用于突发性计算和对延迟和完成时间高度敏感的任务。基于最早截止日期优先(EDF)调度算法。由DL调度器实现。实时进程使用0~99的优先级,就绪进程组织在一个队列中。具有相同优先级的实时进程存储在一个列表中,并按照优先级排列。调度程序总是选择优先级最高的进程最先运行。实时进程在以下情况下可以放弃CPU,进程被更高优先级的实时进程抢占。进程进入休眠或挂起状态。进程调用sched_yield()主动让出CPU。当使用SCHED_RR策略时,进程的时间片被耗尽。普通进程的调度策略有3种,由CFS调度器实现,分别是:SCHED_NORMAL、SCHED_BATCH、SCHED_IDLE。SCHED_NORMAL:(也叫SCHED_OTHER)用于普通进程,由CFS调度器实现。SCHED_BATCH:SCHED_NORMAL策略的差异化版本,采用分时策略,根据动态优先级分配CPU计算资源。SCHED_IDLE:优先级最低,在系统空闲时运行此类进程。调度设置功能Linux进程调度的介绍只是简单的介绍,主要是为了概念的普及和实用。以下是与调度相关的函数的简要列表。nice():调整普通进程的优先级,nice值从-20到19。getpriority()/setpriority():获取/设置线程的优先级。sched_getscheduler()/sched_setscheduler():获取/设置线程的调度策略。sched_getparam()/sched_getparam():获取/设置线程的调度参数,参数由structsched_pa??ram描述。sched_get_priority_max()/sched_get_priority_min():获取指定策略的最大/最小优先级。sched_rr_get_interval():获取实时进程在SCHED_RR策略下的时间片长度。sched_getattr()/sched_setattr():获取/设置调度策略和属性。该接口是其他调度函数的超集。sched_getaffinity()/sched_setaffinity():获取/设置线程的CPU亲和性(affinity)。sched_yield():当前线程主动让出CPU让其他线程执行。Affinity表示CPU的亲和性,就是让进程尽可能长时间地运行在指定的CPU上,而不会被迁移到其他处理器上,也称为CPU亲和性。简单一点的描述就是将指定的进程或线程绑定到对应的CPU上。在多核机器上,每个CPU都有自己的缓存,缓存了进程使用的信息。如果进程被调度到其他CPU,缓存命中率会降低。绑定CPU时,程序会一直运行在指定的CPU上,不会被调度到其他CPU上,可以提高性能。参考文章:调度器介绍,以及Linux的调度策略进程的说明和Linux进程在其生命周期内的管理和调度(17)