Linux不会随意对进程进行调度。事实上,应用程序会被指派优先级,优先级会对进程何时运行以及运行多久造成影响。以往,Unix将优先级成为友善值(nice value),因为友善值背后的概念是通过调低一个进程的优先级来“善待”系统上的其他进程,这让其他进程可以使用较多的处理器空间。
友善值可控制一个进程何时运行。Linux会按照优先级(从最高到最低)的顺序来对运行进程进行调度:优先级较高的进程会比优先级较低的进程先运行。友善值还可控制一个进程的时间片大小。
友善值的有效范围从-20到19,而且默认值是0。你可能会有点困惑,一个进程的友善值越低,则它的优先级就越高,而且它的时间片也越大;反过来说,友善值越高,进程的优先级越低,而且它的时间片越小。因此掉高一个进程的友善值就等于善待系统上的其他进程。但是以数字来看的确令人混淆。当我们说一个进程具有“高优先级”时,我们的意思是说,相较于优先级较低的进程,调度程序会更快安排它运行,而且会让它运行更长时间。
nice()
Linux提供了若干可用于取得以及设定的进程友善值的系统调用。nice()是其中最简单的一个:
#include <unistd.h>
int nice (int nic);
执行成功,nice()会使用inc来掉高一个进程的友善值,而且会返回刚才所更新的值.只有具备CAP_SYS_NICE能力的进程(实际上就是root所拥有的进程)可以对inc提供一个负值来调低它的友善值,因而会掉高它的优先级.因此,拥有者非root的进程只能调低它们的优先级.
发生错误时,nice()会返回-1。然后,因为nice会返回新的友善值,所以-1也是执行成功时的返回值.为了有所区别,调用nice之前,你可以先将errno清为0并在事后检查它的值.例如
发生错误时,Linux只会返回单一错误代码EPERM,这表示进行调用的进程掉高了它的优先级,但是它并不具备CAP_SYS_NICE能力.当让如inc的友善值超越有效值的范围时,有的系统还会返回EINVAL,但是Linux不会.事实上,有需要时,Linux会将无效的inc自动调整至此限度所允许的范围之内.
往往一个进程会想要设定一个攫夺的友善值,而不是设定一个相对增加的友善值.
getpriority()和setpriority()
一个更好的解决方案就是使用getpriority()和setpriority()系统调用,它们提供了较多的控制能力,但是它们的操作也更为复杂:
#include <sys/time.h>
#include <sys/resource.h>
int getpriority(int which, int who);
int setpriority(int which, int who);
这两个系统调用可用于操作进程、进程组或用户,可以通过which或who来指定。which的值必须是PRIO_PROCESSS、PRIO_PRGP、PRIO_USER其中之一,在此情况下,who可分别用于指定进程ID、进程组ID、或用户ID。
getpriority()会返回指定的任何进程中优先级最高者。而setprotity()会将所指定的任何进程的优先级设定为prio。如同nice(),只有具备CAP_SYS_NICE能力的进程可以调高进程的优先级。此外,只有具备此能力的进程可以调高或调低非进行调用的用户所拥有的进程的优先级。
如同nice(),发生错误是,getprioriy()会返回-1。因为执行成功时也会返回此值,如果程序设计者想要处理错误情况,则进行调用之前,它们应该先清除errno的值。setpriority()并没有这个问题,执行成功时,setpriority()总是会返回0,发生错误时,则会返回-1。
下面的程序代码会返回当前进程的优先级:
下面的程序代码会将当前进程组中的所有进程的优先级设定成10:
发生错误时,这两个函数会将errno设定成下面的其中一个值EACCESS、EINVAL、EPRRM、ESRCH
I/O优先级
除了调度优先级,Linux还允许进程指定I/O优先级,此值会影响进程I/O请求的相对优先级。内核的调度程序在服务来自I/O优先级较低的请求之前,会先服务来自I/O优先级较高进程的请求。
默认情况下,I/O调度程序会使用进程的友善值来确定I/O优先级,因此,设定友善值会自动变更I/O优先级。然而Linux内核额外提供了两个系统调用,可用于显示设定和取得与友善值无关的I/O优先级:
int ioprio_get(int which, int who);
int ioprio_set(int which, int who, int ioprio);
并未所有的I/O调度程序都支持I/O优先级。特别的是,完全公平队列(Complete Fair Queuing,CFQ) I/O调度程序就支持I/O优先级;就目前而言,其他的标准调度程序并不支持I/O优先级。如果当前I/O调度程序不支持I/O优先级,它们会默默予以忽略。