Linux內核學習筆記(6)-- 進程優先順序詳解(prio、static_prio、normal_prio、rt_priority)

来源:https://www.cnblogs.com/tongye/archive/2018/09/10/9615625.html
-Advertisement-
Play Games

Linux 中採用了兩種不同的優先順序範圍,一種是 nice 值,一種是實時優先順序。在上一篇粗略的說了一下 nice 值和實時優先順序,仍有不少疑問,本文來詳細說明一下進程優先順序。linux 內核版本為 linux 2.6.34 。 進程優先順序的相關信息,存放在進程描述符 task_struct 中: ...


  Linux 中採用了兩種不同的優先順序範圍,一種是 nice 值,一種是實時優先順序。在上一篇粗略的說了一下 nice 值和實時優先順序,仍有不少疑問,本文來詳細說明一下進程優先順序。linux 內核版本為 linux 2.6.34 。

  進程優先順序的相關信息,存放在進程描述符 task_struct 中:

struct task_struct {
        ...
    int prio, static_prio, normal_prio;
    unsigned int rt_priority;
        ...
}

  可以看到,有四種進程優先順序: prio、static_prio、normal_prio 和 rt_priority,它們的具體定義在 kernel/sched.c 中,在介紹這四種優先順序之前,先介紹一下以下巨集定義:

/* linux-kernel 2.6.34 /include/linux/sched.h */

/*
 * Priority of a process goes from 0..MAX_PRIO-1, valid RT
 * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH
 * tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority
 * values are inverted: lower p->prio value means higher priority.
 *
 * The MAX_USER_RT_PRIO value allows the actual maximum
 * RT priority to be separate from the value exported to
 * user-space.  This allows kernel threads to set their
 * priority to a value higher than any user task. Note:
 * MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO.
 */

#define MAX_USER_RT_PRIO     100
#define MAX_RT_PRIO          MAX_USER_RT_PRIO

#define MAX_PRIO            (MAX_RT_PRIO + 40)
#define DEFAULT_PRIO        (MAX_RT_PRIO + 20)    // 預設優先順序,對應 nice 值為 0 的靜態優先順序

 

1、prio 動態優先順序

  prio 的值是調度器最終使用的優先順序數值,即調度器選擇一個進程時實際選擇的值。prio 值越小,表明進程的優先順序越高。prio  值的取值範圍是 0 ~ MAX_PRIO,即 0 ~ 139(包括 0 和 139),根據調度策略的不同,又可以分為兩個區間,其中區間 0 ~ 99 的屬於實時進程,區間 100 ~139 的為非實時進程。用語言不好描述,我們通過內核代碼來詳細描述 prio:

/* linux-kernel 2.6.34  /kernel/sched.c  */

#include "sched_idletask.c"
#include "sched_fair.c"
#include "sched_rt.c"
#ifdef CONFIG_SCHED_DEBUG
#include "sched_debug.c"
#endif

/*
 * __normal_prio - return the priority that is based on the static prio
 */
static inline int __normal_prio(struct task_struct *p)    // _normal_prio 函數,返回靜態優先順序值
{
    return p->static_prio;
}

/*
 * Calculate the expected normal priority: i.e. priority
 * without taking RT-inheritance into account. Might be
 * boosted by interactivity modifiers. Changes upon fork,
 * setprio syscalls, and whenever the interactivity
 * estimator recalculates.
 */
static inline int normal_prio(struct task_struct *p)    // normal_prio 函數
{
    int prio;

    if (task_has_rt_policy(p))                 // task_has_rt_policy 函數,判斷進程是否為實時進程,若為實時進程,則返回1,否則返回0
        prio = MAX_RT_PRIO-1 - p->rt_priority;        // 進程為實時進程,prio 值為實時優先順序值做相關運算得到: prio = MAX_RT_PRIO -1 - p->rt_priority
    else
        prio = __normal_prio(p);                // 進程為非實時進程,則 prio 值為靜態優先順序值,即 prio = p->static_prio
    return prio;
}

/*
 * Calculate the current priority, i.e. the priority
 * taken into account by the scheduler. This value might
 * be boosted by RT tasks, or might be boosted by
 * interactivity modifiers. Will be RT if the task got
 * RT-boosted. If not then it returns p->normal_prio.
 */
static int effective_prio(struct task_struct *p)       // effective_prio 函數,計算進程的有效優先順序,即prio值,這個值是最終調度器所使用的優先順序值
{
    p->normal_prio = normal_prio(p);              // 計算 normal_prio 的值
    /*
     * If we are RT tasks or we were boosted to RT priority,
     * keep the priority unchanged. Otherwise, update priority
     * to the normal priority:
     */
    if (!rt_prio(p->prio))
        return p->normal_prio;                  // 若進程是非實時進程,則返回 normal_prio 值,這時的 normal_prio = static_prio
    return p->prio;                         // 否則,返回值不變,依然為 prio 值,此時 prio = MAX_RT_PRIO -1 - p->rt_priority
} 

/*********************** 函數 set_user_nice ****************************************/
void set_user_nice(struct task_struct *p, long nice)
{
     ....
    p->prio = effective_prio(p);                   // 在函數 set_user_nice 中,調用 effective_prio 函數來設置進程的 prio 值
     ....
}

  從上面代碼中我們知道,當進程為實時進程時, prio 的值由實時優先順序值(rt_priority)計算得來;當進程為非實時進程時,prio 的值由靜態優先順序值(static_prio)得來。即:

prio = MAX_RT_PRIO - 1 - rt_priority    // 進程為實時進程

prio = static_prio          // 進程為非實時進程

  簡單計算上面的兩個式子,可以知道,prio 值的範圍是 0 ~ 139 。

 

2、static_prio 靜態優先順序

  靜態優先順序不會隨時間改變,內核不會主動修改它,只能通過系統調用 nice 去修改 static_prio,如下:

/*
 * Convert user-nice values [ -20 ... 0 ... 19 ]
 * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ],
 * and back.
 */
#define NICE_TO_PRIO(nice)    (MAX_RT_PRIO + (nice) + 20)
#define PRIO_TO_NICE(prio)    ((prio) - MAX_RT_PRIO - 20)
#define TASK_NICE(p)        PRIO_TO_NICE((p)->static_prio)

/*
 * 'User priority' is the nice value converted to something we
 * can work with better when scaling various scheduler parameters,
 * it's a [ 0 ... 39 ] range.
 */
#define USER_PRIO(p)        ((p)-MAX_RT_PRIO)
#define TASK_USER_PRIO(p)    USER_PRIO((p)->static_prio)
#define MAX_USER_PRIO        (USER_PRIO(MAX_PRIO))

/********************* 函數 set_user_nice *****************************/
p->static_prio = NICE_TO_PRIO(nice);        // 當有需要時,系統會通過調用 NICE_TO_PRIO() 來修改 static_prio 的值

 

  由上面代碼知道,我們可以通過調用 NICE_TO_PRIO(nice) 來修改 static_prio  的值, static_prio 值的計算方法如下:

static_prio = MAX_RT_PRIO + nice +20

  MAX_RT_PRIO 的值為100,nice 的範圍是 -20 ~ +19,故 static_prio 值的範圍是 100 ~ 139。 static_prio 的值越小,表明進程的靜態優先順序越高

 

3、normal_prio 歸一化優先順序

  normal_prio 的值取決於靜態優先順序和調度策略,可以通過 _setscheduler 函數來設置 normal_prio 的值 。對於非實時進程,normal_prio 的值就等於靜態優先順序值 static_prio;對於實時進程,normal_prio = MAX_RT_PRIO-1 - p->rt_priority。代碼如下:

static inline int normal_prio(struct task_struct *p)    // normal_prio 函數
{
    int prio;

    if (task_has_rt_policy(p))                 // task_has_rt_policy 函數,判斷進程是否為實時進程,若為實時進程,則返回1,否則返回0
        prio = MAX_RT_PRIO-1 - p->rt_priority;        // 進程為實時進程,prio 值為實時優先順序值做相關運算得到: prio = MAX_RT_PRIO -1 - p->rt_priority
    else
        prio = __normal_prio(p);                // 進程為非實時進程,則 prio 值為靜態優先順序值,即 prio = p->static_prio
    return prio;
}

 

 

4、rt_priority 實時優先順序

  rt_priority 值的範圍是 0 ~ 99,只對實時進程有效。由式子:

prio = MAX_RT_PRIO-1 - p->rt_priority; 

  知道,rt_priority 值越大,則 prio 值越小,故 實時優先順序(rt_priority)的值越大,意味著進程優先順序越高

  rt_priority 的值也是取決於調度策略的,可以在 _setscheduler 函數中對 rt_priority 值進行設置。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 類的定義 類是描述具有相同特征與行為的事物的抽象,類內部包含類的特征和類的行為 類支持繼承 類的定義是關鍵字class為標誌 類的格式 訪問標識符 class 類名 { 類主體 } 訪問標識符:指定了類及其成員的訪問規則。如果不指定則使用預設的標識符 類的預設標識符為internal,而類成員的預設 ...
  • 概述 在上面一篇 Windows Community Toolkit 4.0 - DataGrid - Part02 中,我們針對 DataGrid 控制項的 Utilities 部分做了詳細分享。而在本篇,我們會對控制項中最重要的 DataGrid 文件夾中的類做詳細的分享。 下麵是 Windows ...
  • 參數 var list = new List<int>(); // 集合var totalCount = 17; // 總數量var pageSize = 5; // 每頁查詢數量 第一種: var pageTotal = totalCount % pageSize == 0 ? totalCoun ...
  • 之前的博客 將時間作為GUID的方法 中,我使用了鎖。我在實際的使用中,錯將鎖的釋放放在了if語句中,這純粹是我的失誤,導致了很嚴重的錯誤。因此我在想是否有無鎖的將時間作為GUID的方式,答案是使用Interlocked中的 CompareExchange方法,該方法是原子操作。說是無鎖操作,其實就 ...
  • 方法是什麼 方法是C#中將一堆代碼進行進行重用的機制 他是在類中實現一種特定功能的代碼塊,將重覆性功能提取出來定義一個新的方法 這樣可以提高代碼的復用性,使編寫程式更加快捷迅速 方法格式 訪問修飾符 返回類型 方法名稱(參數列表) { 方法體; } 方法是在類或結構中聲明的,聲明時需要訪問修飾符、返 ...
  • 記得前面老周寫過在.net core 中使用 Composition 的爛文。上回老周給大伙伴們介紹的是一個“重量級”版本—— System.ComponentModel.Composition。應該說,這個“重量級”版本是.NET 框架中的“標配”。 很多東西都會有雙面性,MEF 也一樣,對於擴展 ...
  • Docker 相關的基礎知識點非常多,比如基本概念,鏡像管理,數據捲(容器)管理,常用命令,周邊生態等等。在這裡梳理出個大概框架,方便後續學習使用。《Docker 遇見前端》系列文章,旨在分享學習如何通過 docker 構建一個相對完備的前端自動化開發環境。 ...
  • 儘管Linux系統非常強大,穩定,但是我們在使用過程當中,如果人為操作不當,仍然會影響系統,甚至可能使得系統無法開機,無法運行服務等等各種問題。那麼這篇博文就總結一下一些常見的故障排除方法,但是不可能面面俱到,只能不斷的補充,更新。 一、管理員忘記密碼 (1)、重啟電腦,進入單用戶模式 1 2 3 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...