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);
}