Linux内核进程管理基本概念-进程、运行队列、等待队列、进程切换、进程调度
下面簡述一些基本概念,以及對內(nèi)核代碼做最初步的了解;
?
一 Linux內(nèi)核進程管理基礎(chǔ)
?
? ? Linux 內(nèi)核使用 task_struct 數(shù)據(jù)結(jié)構(gòu)來關(guān)聯(lián)所有與進程有關(guān)的數(shù)據(jù)和結(jié)構(gòu),Linux 內(nèi)核所有涉及到進程和程序的所有算法都是圍繞該數(shù)據(jù)結(jié)構(gòu)建立的,是內(nèi)核中最重要的數(shù)據(jù)結(jié)構(gòu)之一。
 ? ? 該數(shù)據(jù)結(jié)構(gòu)在內(nèi)核文件 include/linux/sched.h 中定義,是個很大的結(jié)構(gòu)體;在 3.8 的內(nèi)核中,該數(shù)據(jù)結(jié)構(gòu)有 380 行。
? ? Linux中進程ID有如下類型:PID,TGID,PGID,SID;
 ? ? 如果考慮進程之間有復(fù)雜的關(guān)系,如線程組、進程組、會話組,這些組均有組ID;分別為 TGID、PGID、SID;
? ? 內(nèi)核中使用下面兩個函數(shù)來實現(xiàn)分配和回收PID:
 ? ? static int alloc_pidmap(struct pid_namespace *pid_ns);
 ? ? static void free_pidmap(struct upid *upid);
? ? Linux中增加命名空間這個概念是為了虛擬化和方便管理。
 ? ? 進程命名空間;作用:linux通過命名空間管理進程號,在不同的namespace中可以有pid相同的進程;進程命名空間是一個父子結(jié)構(gòu),子空間對于父空間可見。
?
二 task_struct結(jié)構(gòu)
? ??Linux用task_struct結(jié)構(gòu)表示進程,2.6內(nèi)核的task_struct結(jié)構(gòu)相對于2.4內(nèi)核有很大變化。
 ? ? 該結(jié)構(gòu)記錄了進程的重要信息。
 ? ? 與進程調(diào)度有關(guān)的信息包括:
 ? ? 1 state
? ? 進程狀態(tài);一個進程共有7種可能狀態(tài),分別是:TASK_RUNNING、TASK_INTERRUPTIBLE、TASK_UNINTERRUPTIBLE、TASK_STOPPED、TASK_TRACED、EXIT_ZOMBIE和EXIT_DEAD;
? ? 2 timestamp
? ? 進程發(fā)生調(diào)度事件的時間(單位是?nanosecond)。
 ? ? 3 prio,?static_prio
? ? 進程的優(yōu)先級和靜態(tài)優(yōu)先級。Prio表示進程的動態(tài)優(yōu)先級,與2.4內(nèi)核中g(shù)oodness()的計算結(jié)果相當(dāng)。在0~MAX_PRIO-1之間取值(MAX_PRIO?定義為?140),其中0~MAX_RT_PRIO-1(MAX_RT_PRIO定義為100)屬于實時進程范圍,MAX_RT_PRIO~MX_PRIO-1屬于非實時進程。數(shù)值越大,表示進程優(yōu)先級越小。static_prio表示進程的靜態(tài)優(yōu)先級,相當(dāng)于2.4內(nèi)核中的nice。一個進程的初始時間片的大小完全取決于它的靜態(tài)優(yōu)先級。
 ? ? 4 sleep_avg
? ? 進程的平均等待時間,在0到NS_MAX_SLEEP_AVG之間取值,初值為0,相當(dāng)于進程等待時間與運行時間的差值。它是動態(tài)優(yōu)先級計算的關(guān)鍵因子,sleep_avg越大,計算出來的進程優(yōu)先級也越高。
 ? ? 5 interactive_credit
? ? 該變量表示進程的交互程度。在-CREDIT_LIMIT到CREDIT_LIMIT+1之間取值,初始值為0,而后根據(jù)不同的條件加1減1,一旦該值超過CREDIT_LIMIT,即表示該進程是交互進程。
 ? ? 6 array
? ? 指向當(dāng)前CPU的active就緒進程隊列。
 ? ? 7 run_list
? ? ?進程通過這個list_head變量連接自己到prio_array數(shù)組中queue隊列,這樣相同優(yōu)先級的進程連接成一個雙向列表,表頭為prio_array結(jié)構(gòu)中的queue變量。
?
三 進程運行隊列(就緒隊列)
?
? ? Linux內(nèi)核定義了一個list_head數(shù)據(jù)結(jié)構(gòu),字段head和prev分別表示通用的雙向鏈表向前和向后的指針元素。每個task_struct包含一個list_head類型的run_list字段。
? ? 在Linux2.4內(nèi)核中,就緒進程隊列是一個全局數(shù)據(jù)結(jié)構(gòu),所有的處理器共享同一個隊列。調(diào)度器對它的所有操作都會因全局自旋鎖而導(dǎo)致系統(tǒng)各個處理機之間的等待,使得就緒隊列成為一個明顯的瓶頸。2.6內(nèi)核重新設(shè)計就緒進程隊列為每CPU的數(shù)據(jù)結(jié)構(gòu),每個處理器都維護一個自己的就緒隊列,這樣就避免了2.4內(nèi)核中的SMP性能瓶頸。
?
? ? 每個CPU的就緒進程隊列由一個struct runqueue結(jié)構(gòu)描述,其中最關(guān)鍵的子結(jié)構(gòu)是優(yōu)先級就緒數(shù)組。
? ? 描述優(yōu)先級就緒數(shù)組的數(shù)據(jù)結(jié)構(gòu)是prio_array_t。
?
四 進程等待隊列
?
? ? Linux等待隊列在內(nèi)核中有很多用途,尤其在中斷處理、進程同步以及定時。例如等待一個磁盤操作的終止,等待釋放資源,或等待時間經(jīng)過的固定的時間間隔。
? ??
等待隊列由雙向鏈表實現(xiàn)。
?
struct?__wait_queue_head?{??
????????spinlock_t?lock;??
????????struct?list_head?task_list;??
};??//等待隊列的頭結(jié)點
typedef?struct__wait_queue_head?wait_queue_head_t;
?
struct?__wait_queue?{
? ? unsigned?int?flags;?//標(biāo)識是互斥進程還是非互斥進程?
?????? ?#define WQ_FLAG_EXCLUSIVE??????0x01??/*?表示等待進程想要被獨占地喚醒??*/??
????????void?*private; ?/*?指向等待進程的task_struct實例?*/??????????
 ? ? ? ? wait_queue_func_t?func;??????/*?用于喚醒等待進程?? ? ?*/??????????
 ? ? ? ?sruct?list_head?task_list;??/*?用于鏈表元素,將wait_queue_t鏈接到wait_queue_head_t?*/?
};
typedef?struct__wait_queue?wait_queue_t;??
?
五 進程切換
?
? ? 內(nèi)核必須有能力掛起正在CPU上運行的進程,并恢復(fù)以前掛起的某個進程執(zhí)行。這種行為稱為進程切換、任務(wù)切換或上下文切換。
 ? ? 盡管每個進程都擁有屬于自己的地址空間,但所有進程必須共享CPU寄存器。在恢復(fù)一個進程的執(zhí)行之前,內(nèi)核必須確保每個寄存器裝了掛起進程時的值。
 ? ? 進程恢復(fù)前必須裝入寄存器的一組數(shù)據(jù)稱為硬件上下文,它的一部分存在TSS段,而剩余部分存放在內(nèi)核態(tài)堆棧中。
? ??
 ? ? 每個進程描述符包含一個類型thread_struct的thread字段,來保存進程切換時的硬件上下文。
 ? ? 進程切換主要有兩大步:1、切換全局頁表項;2、切換內(nèi)核堆棧和硬件上下文。這個切換工作由context_switch()完成。其中switch_mm完成第一步,而switch_to和__switch_to()主要完成第二步。更詳細的,__switch_to()主要完成硬件上下文切換,switch_to主要完成內(nèi)核堆棧切換。
? ? ? ? schedule() --> context_switch() --> switch_to --> __switch_to()
?
六 進程調(diào)度
?
進程調(diào)度由schedule()函數(shù)實現(xiàn)。
Linux的進程調(diào)度是基于分時技術(shù)(time-sharing)。允許多個進程“并發(fā)”運行就意味著CPU 的時間被粗略地分成“片”,給每個可運行進程分配一片。
調(diào)度策略也是基于依照優(yōu)先級排隊的進程。
 在Linux 中,進程的優(yōu)先級是動態(tài)的。調(diào)度程序跟蹤進程做了些什么,并周期性地調(diào)整它們的優(yōu)先級。在這種方式下,在較長的時間間隔內(nèi)沒有使用CPU的進程,通過動態(tài)地增加它們的優(yōu)先級來提升它們。相應(yīng)地,對于已經(jīng)在CPU上運行了較長時間的進程,通過減少它們的優(yōu)先級來處罰它們。每個進程在創(chuàng)建之初有一個基本的優(yōu)先級,執(zhí)行期間調(diào)度系統(tǒng)會動態(tài)調(diào)整它的優(yōu)先級,交互性高的任務(wù)會獲得一個高的動態(tài)優(yōu)先級,而交互性低的任務(wù)獲得一個低的動態(tài)優(yōu)先級。
Linux操作系統(tǒng)支持多進程,進程控制塊PCB(Process ControlBlock)是系統(tǒng)中最為重要的數(shù)據(jù)結(jié)構(gòu)之一。用來存放進程所必需的各種信息,PCB用結(jié)構(gòu)task_struct來表示,包括進程的類型、進程狀態(tài)、優(yōu)先級、時鐘信息等。
Linux系統(tǒng)中,進程調(diào)度操作由schedule()函數(shù)執(zhí)行,這是一個只在內(nèi)核態(tài)運行的函數(shù),函數(shù)代碼為所有進程共享。
?
 更多詳情自行參閱如下;
 https://www.cnblogs.com/hazir/p/linux_kernel_pid.html
 https://blog.csdn.net/sdulibh/article/details/50827911
 https://www.jianshu.com/p/c1c5e347d64c
 https://blog.csdn.net/lsjseu/article/details/9249665
 ?
總結(jié)
以上是生活随笔為你收集整理的Linux内核进程管理基本概念-进程、运行队列、等待队列、进程切换、进程调度的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: CPU实模式和保护模式、全局描述符表GD
- 下一篇: 使用CFree调用Win32 LoadL
