posix多线程有感--线程高级编程(进程的优先级)
作为多任务的操作系统,Linux内核为每个创建的进程分配时间片并根据其优先级进行调度。当进程被创建时,其对应的task_struct里包含了四个优先级:
struct task_struct {
……
int prio, static_prio, normal_prio;
unsigned int rt_priority;
……
};
在内核头文件include/linux/sched.h中定义了如下宏
#define MAX_USER_RT_PRIO 100
#define MAX_RT_PRIO MAX_USER_RT_PRIO
#define MAX_PRIO (MAX_RT_PRIO + 40)
内核中规定进程的优先级范围为[0, MAX_PRIO-1]。其中实时任务的优先级范围是[0, MAX_RT_PRIO-1],非实时任务的优先级范围是[MAX_RT_PRIO, MAX_PRIO-1]。优先级值越小,意味着级别越高,任务先被内核调度。
那任务的优先级又是如何确定的呢?和task_struct中的成员是什么关系?
- prio指的是任务当前的动态优先级,其值影响任务的调度顺序。
- normal_prio指的是任务的常规优先级,该值基于static_prio和调度策略计算。
- static_prio指的是任务的静态优先级,在进程创建时分配,该值会影响分配给任务的时间片的长短和非实时任务动态优先级的计算。
- rt_priority指的是任务的实时优先级。若为0表示是非实时任务,[1, 99]表示实时任务,值越大,优先级越高。
实时进程的优先级
在调用函数sched_setscheduler()设置实时进程优先级时,最终调用了下面的函数
其中进程的rt_priority就等于配置给进程的优先级,而进程的normal_prio=MAX_RT_PRIO-1 - p->rt_priority; p->prio =p->normal_prio;即 prio和normal_prio都与rt_priority成反比。
我们知道,在调度时使用了prio,其数值0对应最高优先级,99为最低实时优先级。Prio和normal_prio 数值越大优先级越小,而rt_priority的数值越大优先级越大。
这就是为什么有人说实时进程优先级数值越小优先级越高,也有人说实时进程优先级数值越大优先级越高的原因。
另外,实时进程只是用了四个优先级变量中的三个(prio、normal_prio和rt_priority),而没有使用static_prio。
普通进程的优先级
在调用接口set_user_nice()设置普通进程的优先级时,可以自己顺着函数set_user_nice()查看下面的关系。
p->static_prio = NICE_TO_PRIO(nice);
p->prio = effective_prio(p); 即p->prio = p->static_prio;
p->normal_prio = p->static_prio 参见函数effective_prio(p);
结论是:非实时进程的static_prio、prio和normal_prio 一直保持相同。
另外,从函数effective_prio()来看,非实时进程的动态优先级等于其静态优先级。内核不再动态修改其优先级。
总结:
rt_priority缺省值为0,表示非实时任务。[1,99]表示实时任务
对于非实时任务,prio = normal_prio = static_prio static_prio = MAX_RT_PRIO + 20 + nice(nice的缺省值是0,范围[-20, 19])
对于实时任务 prio = normal_prio = MAX_RT_PRIO – 1 – rt_priority 没有使用static_prio
prio的值在使用实时互斥量时会暂时提升,释放后恢复成normal_prio
下面来了解一下如何在应用程序中改变进程的优先级。
#include <sys/time.h>
#include <sys/resource.h>
int setpriority(int which, int who, int prio);
//该函数可以修改进程、进程组或用户所有进程的nice值从而影响static_prio
which : PRIO_PROCESS // 修改某个进程
PRIO_PGRP // 修改进程组
PRIO_USER // 修改用户所有进程
who : 进程号(0表示当前调用进程)、进程组号或UID
prio : 新的用户态优先级(即nice值,范围[-20,19])
返回值 : 执行成功返回0,失败返回-1并设置errno
……
if (setpriority(PRO_PROCESS, 0, 2) <0)
{
perror(“fail to setpriority”);
exit(-1);
}
……
************************************************************************
#include <sched.h>
int sched_setscheduler(pid_t pid, int policy, const struct sched_param *param);
struct sched_param
{
int sched_priority;
};
// 该函数修改某个进程的调度策略和rt_priority
pid : 要修改的进程号,0表示当前调用进程
policy : 调度策略
SCHED_OTHER(针对非实时进程的调度策略)
SCHED_RR(针对实时进程的轮转调度策略)
SCHED_FIFO(针对实时进程的先进先出调度策略)
param : 指向的结构体中存放着要设置的rt_priority-----------------------------注意与setpriority()的区别,sched_setscheduler设置rt_priority,setpriority()设置的是nice
返回值 : 执行成功返回0,失败返回-1并设置errno
……
struct sched_param sp = {1};
if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0)
{
perror(“fail to sched_setscheduler”);
exit(-1);
}