Linux中的进程优先级

UNIX系统历史上对进程提供了基于调度优先级粗粒度的控制,调度策略和优先级是由内核确定的,内核可以通过调整nice值选择以更低优先级运行。

进程使用CPU的默认策略是时间片轮转,每个进程轮流使用CPU一段时间。

进程优先级

用top或者ps命令会输出PRI/PR、NI、%ni/%nice这三种指标值,这些到底是什么东西?先给出大概的解释如下:

PRI是进程的优先级,程序被CPU执行的先后顺序,值越小优先级越高。

NI是nice值,表示进程可被执行的优先级的修正数值。PRI值越小越快被执行,加入nice值后,PRI变为:PRI(new)=PRI(old)+nice。PR是根据NICE排序的,NICE越小PR越前(小,优先权更大),即其优先级会变高,则其越快被执行。如果NICE相同则进程uid是root的优先权更大。

假设在一个CPU轮转中,有2个runnable的进程A和B,他们的nice值都为0,假设内核会给他们每人分配1k个cpu时间片。但是假设进程A的为0,但是B的值为-10,那么此时CPU可能分别给A和B分配1k和1.5k的时间片。nice的值影响了内核分配给进程的cpu时间片的多少,时间片越多的进程,其优先级越高,其优先级值(PRI)越低。%nice,就是改变过优先级的进程的占用CPU的百分比,如上例中就是0.5k/2.5k=15=20%。

进程nice值和进程优先级不是一个概念,但是进程nice值会影响到进程的优先级变化。

nice值

进程特性nice值运行进程间接地影响内核的调度算法:

这样做之后这个进程就对其他进程十分“友好(nice)”了。

在使用fork()创建子进程时会继承nice值并且该值会在exec()调用中得到保持。

nice值的影响

从版本号为 2.6.23 的内核开始,nice 值之间的差别对新内核调度算法的影响比对之前的内核中的调度算法的影响要强。因此,低 nice 值的进程使用 CPU 的时间将比以前少,高nice 值的进程占用 CPU 的时间将大大提高

nice值的的修改

进程的nice值是可以被修改的,修改命令分别是nice和renice。

  1. nice命令就是设置一个要执行command进程的nice值,其命令格式是 nice –n adjustment command command_option,如果这里不指定adjustment,则默认为10。
  2. renice命令就是设置一个已经在运行的进程的nice值,假设一运行进程本来nice值为0,renice为3后,则这个运行进程的nice值就为3了。

nice()

#include<unistd.h>
int nice(int incr); //返回值:若成功,返回新的nice值;若出错,返回-1

incr被增加到调用进程的nice值上。如果nice超过范围,都会被修改到合法值。

以前 nice 值是通过调用nice(incr)来完成的,这个函数会将调用进程的nice值加上incr。现在这个函数仍然是可用的,但已经被更通用的setpriority()系统调用所取代了。

在命令行中与setpriority()系统调用实现类似功能的命令是nice(1),非特权用户可以使用这个命令来运行一个优先级更低的命令,特权用户则可以运行一个优先级更高的命令,超级用户则可以使用 renice(8)来修改既有进程的nice值。

getpriority和setpriority

#include <sys/resource.h>

int getpriority(int which, id_t who);

int setpriority(int which, id_t who, int prio);

getpriority()函数可以像nice函数获取进程nice值,而且他还可以获取一组相关进程的nice值. setpriority()函数可用于进程、进程组和属于特定用户ID的所有进程设置优先级:

描述

进程、进程组或用户的调度优先级,由which和who表示,通过getpriority()调用获得,通过setpriority()调用设置。 which是PRIO_PROCESS、PRIO_PGRP或者PRIO_USER中的一个,而who是相对于which(PRIO_PROCESS的进程标识符,PRIO_PGRP的进程组标识符,以及PRIO_USER的用户ID)解释的。 who的零值表示当前进程、进程组或用户。 prio是一个范围在-20到20的值。 默认的优先级是0;较低的优先级会导致更有利的调度。

getpriority()调用返回任何指定进程所享有的最高优先级(最低数值)。 setpriority()调用将所有指定进程的优先级设置为指定值。只有超级用户可以降低优先级。

此外,通过为which指定PRIO_DARWIN_THREAD或PRIO_DARWIN_PROCESS,可以将当前线程或进程置于后台状态。 在设置或获取背景状态时,只支持对谁的值为0(当前线程或进程)。 prio为0(将当前线程从背景状态中移除)或PRIO_DARWIN_BG(将当前线程设置为背景状态)。 当一个线程或进程处于后台状态时,调度优先级被设置为最低值,磁盘IO被节制(其行为类似于使用setiopolicy_np(3)来设置可节制策略),网络IO对于进入后台状态后打开的任何套接字都被节制。 任何先前打开的套接字都不受影响。 当当前线程或进程没有进入后台状态时,getpriority()调用返回0,当当前线程进入后台状态时,getpriority()调用返回1。 任何线程或进程都可以将自己设置为背景状态。

返回值

由于getpriority()可以合法地返回值-1,因此有必要在调用前清除外部变量errno,然后在调用后检查它以确定-1是一个错误还是一个合法的值。 如果没有错误,setpriority()调用会返回0,如果有,则返回1。

参考资料:

  1. https://zhuanlan.zhihu.com/p/514634555
  2. http://wuyudong.com/2016/11/21/3070.html
  3. https://blog.csdn.net/zhizhengguan/article/details/117434191
  4. https://www.cfanz.cn/resource/detail/pJvgEvvqEwkXK