概述
在多任务操作系统中,进程优先级是一个非常重要的概念,决定了进程获取CPU时间的能力。合理的优先级管理,不仅可以提升系统的整体性能,还能确保关键任务得到及时的处理。
进程优先级是一个数值指标,主要用于衡量操作系统调度CPU时间给进程时的优先程度。在Linux中,进程优先级分为两种:静态优先级和动态优先级。
静态优先级:由用户或系统管理员设定的优先级,通常通过nice值来表示。静态优先级的范围从-20(最高优先级)到19(最低优先级),默认值为0。静态优先级主要用于区分不同类型的用户进程,以便于系统在资源紧张时,可以做出合理的调度决策。
动态优先级:由调度器根据进程的行为,自动调整的优先级。动态优先级的变化取决于进程的CPU使用情况、I/O活动等因素。在Linux的完全公平调度器(即CFS)中,动态优先级通过虚拟运行时间来计算,以确保长时间未获得CPU时间的进程能够尽快得到执行机会。
静态优先级和动态优先级是相互关联的。静态优先级作为基本优先级,在进程创建时确定,并作为动态优先级计算的基础。动态优先级则根据进程的运行情况和行为进行调整,以反映进程在运行时的实际优先级。
优先级类型
在Linux系统中,进程的优先级类型主要包括:普通进程优先级、实时进程优先级、批处理进程优先级,以满足不同应用场景的需求。
1、普通进程优先级:是指非实时、非批处理的进程所具有的优先级。这类进程在系统中最为常见,包括用户运行的图形界面程序、后台服务等。普通进程优先级适用于大多数用户进程,默认使用CFS调度器。普通进程优先级通常通过一个称为“Nice值”的数值来表示。Nice值的范围是-20到19,其中-20表示最高优先级,19表示最低优先级。较低的Nice值表示较高的优先级,而较高的Nice值则表示较低的优先级。
我们可以使用nice命令来启动一个新进程,并设置其Nice值。比如:nice -n 10 ./hope_wisdom,会以Nice值为10来启动hope_wisdom程序。当然,也可以使用renice命令调整已经运行的进程的Nice值。
注意:普通用户通常只能提高自己的Nice值(即降低优先级),而不能降低其他用户的Nice值(即提高优先级),这需要使用超级用户权限。
2、实时进程优先级:适用于对响应时间有严格要求的实时进程,比如实时音频处理、控制系统等。实时进程使用专门的调度策略,比如:SCHED_FIFO(先入先出)和SCHED_RR(时间片轮转)。实时进程的优先级范围从0到99,其中0是最高的优先级。
实时进程的优先级非常高,能够确保在指定的时间内得到响应和执行。这对于需要严格时间控制的多媒体应用和实时控制系统来说,至关重要。然而,如果系统中存在过多的实时进程,可能会导致CPU资源被过度占用,从而影响其他进程的执行。
我们可以使用chrt命令设置实时进程的调度策略和优先级。比如:chrt -f 66 ./hope_wisdom,会以实时FIFO策略启动hope_wisdom程序,并设置其优先级为66。
3、批处理进程优先级:是指那些不需要立即执行,可以在系统负载较低时运行的进程。这类进程通常用于执行批处理作业,比如:数据备份、数据分析、打印队列管理、文件索引构建等。批处理进程通常具有较低的优先级,以避免干扰前台用户的交互体验。
设置优先级
在Linux中,设置进程的优先级主要有两个函数,分别为:setpriority、sched_setscheduler。
1、setpriority函数:用于设置进程或进程组的静态优先级,从而影响进程在系统中的调度顺序。其函数原型如下:
int setpriority(int which, id_t who, int prio);
which:指定要设置优先级的对象类型,取值如下。
(1)PRIO_PROCESS:设置单个进程的优先级。
(2)PRIO_PGRP:设置进程组的优先级。
(3)PRIO_USER:设置用户的所有进程的优先级。
who:指定对象的标识符,根据which参数的不同,who的含义也不同。
(1)如果which是PRIO_PROCESS,who是进程ID。
(2)如果which是PRIO_PGRP,who是进程组ID。
(3)如果which是PRIO_USER,who是用户ID。如果who是0,则表示当前用户。
prio:要设置的优先级。静态优先级的范围是从-20(最高优先级)到19(最低优先级),默认值为0。
返回值:成功时,返回0。失败时,返回-1,并设置errno为适当的错误码。常见的错误码有:EINVAL(无效的参数或策略)、EPERM(权限不足,尝试设置高于当前进程最大允许优先级的优先级)、ESRCH(指定的进程不存在)。
2、sched_setscheduler函数:用于设置进程的调度策略和优先级。这对于实时应用尤其重要,因为它允许开发者精确控制进程的执行顺序和优先级,确保关键任务能够及时得到处理。其函数原型如下:
struct sched_param
{int sched_priority; // 进程的优先级
};int sched_setscheduler(pid_t pid, int policy, const struct sched_param *param);
pid:进程ID。如果设置为0,则表示当前进程。
policy:调度策略,取值如下。
(1)SCHED_FIFO:先入先出调度策略,适用于实时任务。
(2)SCHED_RR:轮转法调度策略,适用于实时任务,每个进程有一个固定的时间片。
(3)SCHED_OTHER:默认的调度策略,适用于普通用户进程,使用完全公平调度器(即CFS)。
(4)SCHED_BATCH:批处理调度策略,适用于长时间运行的计算密集型任务。
(5)SCHED_IDLE:低优先级调度策略,适用于极低优先级的后台任务。
param:指向sched_param结构体的指针,该结构体包含进程的优先级信息。
返回值:成功时,返回0。失败时,返回-1,并设置errno为适当的错误码。常见的错误码有:EINVAL(无效的参数或策略)、EPERM(权限不足,尝试设置高于当前进程最大允许优先级的优先级)、ESRCH(指定的进程不存在)。