进程优先级管理

时间:2021-08-22 20:48:40
Linux提供一个系统调用运行进程主动让出执行权:sched_yield。进程运行的好好的,为什么需要这个函数呢?有一种情况是用户空间线程的锁定。如果一个线程试图取得另一个线程所持有的锁,则新的线程应该让出处理器直到该锁变为可用。用户空间锁没有内核的支持,这是一个最简单、最有效率的做法。但是现在Linux线程实现引入一个使用futexes的优化解决方案。另一个情况是在有处理器密集型程序可用周期性调用sched_yield,试图将该进程对系统的冲击减到最小。


调整进程在处理器上执行的优先级
1)nice()函数
头文件:#include <unistd.h>
定义函数:int nice(int inc);
函数说明:nice()用来改变进程的进程执行优先顺序. 参数inc 数值越大则优先顺序排在越后面, 即表示进程执行会越慢. 只有超级用户才能使用负的inc 值, 代表优先顺序排在前面, 进程执行会较快
返回值:如果执行成功则返回0, 否则返回-1, 失败原因存于errno中
2)getpriority
#include<sys/time.h>
#include<sys/resource.h>
定义函数 int getpriority(int which,int who);
函数说明
getpriority()可用来取得进程、进程组和用户的进程执行优先权。
参数which有三种数值,参数who则依which值有不同定义:
which who 代表的意义
PRIO_PROCESS who 为进程识别码
PRIO_PGRP who 为进程的组识别码
PRIO_USER who 为用户识别码
返回值
返回进程执行优先权,如有错误发生返回值则为-1且错误原因存于errno。
返回的数值介于-20至20 之间,代表进程执行优先权,数值越低代表有较高的优先次序,执行会较频繁。
附加说明
由于返回值有可能是-1,因此要同时检查errno是否存有错误原因。
最好在调用次函数前先清除errno变量。
错误代码
ESRCH 参数which或who可能有错,而找不到符合的进程
EINVAL 参数which值错误。
3)setpriority
#include<sys/time.h>
#include<sys/resource.h>
int setpriority(int which,int who, int prio);
参数which有三种数值,参数who则依which值有不同定义:
PRIO_USER who为用户识别码
参数prio介于-20至20之间。代表进程执行优先权,数值越低代表有较高的优先次序,执行会较频繁。此优先权默认是0,而只有超级用户(root)允许降低此值。执行成功则返回0,如果有错误发生返回值则为-1,错误原因存于errno。
ESRCH 参数which或who可能有错,而找不到符合的进程
EINVAL 参数which值错误。
EPERM 权限不够,无法完成设置
EACCES 一般用户无法降低优先权


调整传输数据的优先级:I/O优先级
int ioprio_get(int which, int who);
int ioprio_set(int which, int who, int ioprio);
which的取值:
IOPRIO_WHO_PROCESS
who is a process ID or thread ID identifying a single process or thread. If who is 0, then operate on the calling thread.
IOPRIO_WHO_PGRP
who is a process group ID identifying all the members of a process group. If who is 0, then operate on the process group of which the caller is a member.
IOPRIO_WHO_USER
who is a user ID identifying all of the processes that have a matching real UID.


If which is specified as IOPRIO_WHO_PGRP or IOPRIO_WHO_USER when calling ioprio_get(), and more than one process matches who, then the returned priority will be the highest one found among all of the matching processes.


One priority is said to be higher than another one if it belongs to a higher priority class (IOPRIO_CLASS_RT is the highest priority class; IOPRIO_CLASS_IDLE is the lowest) or if it belongs to the same priority class as the other process but has a higher priority level (a lower priority number means a higher priority level).


The ioprio argument given to ioprio_set() is a bit mask that specifies both the scheduling class and the priority to be assigned to the target process(es). The following macros are used for assembling and dissecting ioprio values:
IOPRIO_PRIO_VALUE(class, data)
Given a scheduling class and priority (data), this macro combines the two values to produce an ioprio value, which is returned as the result of the macro.
IOPRIO_PRIO_CLASS(mask)
Given mask (an ioprio value), this macro returns its I/O class component, that is, one of the values IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, or IOPRIO_CLASS_IDLE.
IOPRIO_PRIO_DATA(mask)
Given mask (an ioprio value), this macro returns its priority (data) component.


IOPRIO_CLASS_RT (1)
This is the real-time I/O class. This scheduling class is given higher priority than any other class: processes from this class are given first access to the disk every time. Thus this I/O class needs to be used with some care: one I/O real-time process can starve the entire system. Within the real-time class, there are 8 levels of class data (priority) that determine exactly how much time this process needs the disk for on each service. The highest real-time priority level is 0; the lowest is 7. In the future this might change to be more directly mappable to performance, by passing in a desired data rate instead.
IOPRIO_CLASS_BE (2)
This is the best-effort scheduling class, which is the default for any process that hasn't set a specific I/O priority. The class data (priority) determines how much I/O bandwidth the process will get. Best-effort priority levels are analogous to CPU nice values (see getpriority(2)). The priority level determines a priority relative to other processes in the best-effort scheduling class. Priority levels range from 0 (highest) to 7 (lowest).
IOPRIO_CLASS_IDLE (3)
This is the idle scheduling class. Processes running at this level only get I/O time when no-one else needs the disk. The idle class has no class data. Attention is required when assigning this priority class to a process, since it may become starved if higher priority processes are constantly accessing the disk.


设置处理器亲和力
Linux支持具有多个处理器的单一系统。在SMP上,系统要决定每个处理器上要运行那些程序,这里有两项挑战:
1)调度程序必须想办法充分利用所有的处理器。
2)切换程序运行的处理器是需要代价的。
进程会继承父进程的处理器亲和性,Linux提供两个系统调用用于获取和设定“硬亲和性”。
CPU 亲和性(affinity)就是进程要在某个给定的CPU上尽量长时间地运行而不被迁移到其他处理器的倾向性。在 Linux 内核中,所有的进程都有一个相关的数据结构task_struct。其中与亲和性(affinity)相关度最高的是cpus_allowed位掩码。这个位掩码由n位组成,与系统中的n个逻辑处理器一一对应。 具有4个物理CPU的系统可以有4位。如果这些CPU都启用了超线程,那么这个系统就有一个8位的位掩码。如果为给定的进程设置了给定的位,那么这个进程就可以在相关的 CPU 上运行。因此,如果一个进程可以在任何CPU上运行,并且能够根据需要在处理器之间进行迁移,那么位掩码就全是1。实际上,这就是Linux中进程的缺省状态。
Linux内核API提供了一些方法,让用户可以修改位掩码或查看当前的位掩码:
sched_set_affinity()(用来修改位掩码)
sched_get_affinity()(用来查看当前的位掩码)
http://blog.csdn.net/i_am_jojo/article/details/7592186


设置进程调度策略
http://blog.chinaunix.net/uid-24774106-id-3379478.html
http://blog.csdn.net/sailor_8318/article/details/2460177
可以使用sched_getscheduler来获取进程的调度策略
SCHED_RR
SCHED_FIFO  
SCHED_OTHER
sched_getparam和sched_setparam接口可用于取得、设定一个已经设定好的策略
Linux提供两个用于取得有效优先值的范围的系统调用sched_get_priority_min(SCHED_RR)和sched_get_priority_max(SCHED_RR)
通过sched_rr_get_interval可以取到分配给pid的时间片的长度


Linux对进程加上了若干资源限制,这些限制是一个进程所能耗用的内核资源的上限。限制的类型如下:
RLIMIT_AS:地址空间上限。
RLIMIT_CORE:core文件大小上限。
RLIMIT_CPU:可耗用CPU时间上限。
RLIMIT_DATA:数据段与堆的上限。
RLIMIT_FSIZE:所能创建文件的大小上限。
RLIMIT_LOCKS:文件锁数目上限。
RLIMIT_MEMLOCK:不具备CAP_SYS_IPC能力的进程最多将多少个字节锁进内存。
RLIMIT_MSGQUEUE:可以在消息队列中分配多少字节。
RLIMIT_NICE:最多可以将自己的友善值调多低。
RLIMIT_NOFILE:文件描述符数目的上限。
RLIMIT_NPROC:用户在系统上能运行进程数目上限。
RLIMIT_RSS:内存中页面的数目的上线。
RLIMIT_RTPRIO:不具备CAP_SYS_NICE能力进程所能请求的实时优先级的上限。
RLIMIT_SIGPENDING:在队列中信号量的上限,Linux特有的限制。
RLIMIT_STACK:堆栈大小的上限。