linux進程管理(1)---進程描述符

    linux支持多進程特性,可以最大化的使用cpu資源;用戶可以在同一個cpu上運行多個用戶程序。多進程的原理是:時鐘中斷觸發進程調度程序,調度程序分時運行多個進程。這就要求每個進程能夠保留現場信息(cpu現場、系統資源、調度信息等)。

    linux使用進程描述符數據結構記錄現場信息,然後基於進程描述符管理進程,包括進程的創建、調度、消亡等操作。

    本系列文章將詳細講述進程管理相關的知識,內核版本爲3.10,發行版爲ubuntu12.04。


一、目的

    在介紹進程管理之前,先介紹進程描述符的概念及現場信息,並闡述這些信息的具體含義。


二、進程描述符

    進程不僅僅是運行着的程序,還包括擁有的系統資源、當前cpu現場、調度信息、進程間關係等重要信息,記錄這些現場信息的結構就是進程描述符task_struct(可以在include/linux/sched.h中找到定義)。

    每個進程都有一個進程描述符,記錄以下重要信息:進程標識符、進程當前狀態、棧地址空間、內存地址空間、文件系統、打開的文件、信號量等。

    進程描述符在內存中的存放位置比較有特點。由於系統需要頻繁的獲取當前進程描述符的地址,爲了提高效率,linux巧妙的實現該功能,使用current宏可以快速得到當前進程地址。

    在x86體系中,通過SP寄存器可以快速獲取當前進程棧的位置;linux在棧的末端存放了一個特殊的數據結構thread_infothread_info中存放了指向task_struct的指針。根據這個原理,首先當前進程通過SP寄存器獲取棧的位置,然後根據棧大小(一般爲1-2頁)獲取thread_info的地址,最後通過thread_info獲取當前進程的地址。

    基於以上分析,進程的內核棧與thread_info存放在同一頁內,thread_info與內核棧共享了頁。從源代碼中可以看出,在分配內核棧的同時也分配了thread_info


三、進程ID與線程組ID

    linux不嚴格區分進程與線程,把進程與線程統稱爲輕量級進程,如果某個輕量級進程是線程組長,那麼就是符合POSIX標準定義的進程概念;如果是線程組員,那麼就是符合POSIX標準定義的線程概念。

    根據POSIX標準,一個進程內的所有線程的ID就是該進程的ID,線程自己沒有獨立的線程ID;但是,linux不僅有進程ID,而且給每個線程也分配了線程ID。對於task_struct數據結構的成員來說,pid是線程IDtgid是線程的進程ID(該進程也叫線程組長)。

    經過上面的分析,就不難理解sys_getpid系統調用獲取的是tgidsys_gettid系統調用獲取的是pid。總之,POSIX的進程ID就是tgid成員;POSIX的線程ID就是pid成員。

    linux中有兩個特殊的進程:進程0swapper或者idle)和進程1init)。系統在初始化時靜態建立進程0,並分配了進程ID0;進程1是進程0創建的第一個進程,所以進程1的進程ID1。由於這兩個進程在系統中的地位比較重要,因此通常稱這兩個進程爲進程0、進程1;隱含的表達了進程0就是swapper、進程1就是init


四、進程名稱

    comm成員記錄了當前進程可執行文件的名稱,最大長度爲16個字節。


五、進程狀態

    調度程序根據進程狀態決定是否調度進程,linux是喲概念bitmap(位圖)表示進程狀態,一共有11種狀態;這些狀態可以分爲三類:運行態、睡眠態、退出態。只有運行態的進程才能被調度程序調度;進程等待某個資源時處於睡眠態(可中斷態、不可中斷態);進程退出時處於退出態(殭屍態、死亡態)。其他的進程狀態還包括停止態、跟蹤態等,這些狀態處於特定的使用場景中,就不介紹了。

    運行態:進程在cpu上運行或者等待運行。

    睡眠態:睡眠態分爲可中斷態和不可中斷態。進程因爲等待某個資源而處於睡眠狀態。這兩者的區別是不可中斷態忽略發送過來的喚醒信號量,因爲這個狀態的進程獲取了重要的系統資源,因此不能被輕易打斷,該狀態較少使用。

    退出態:退出態分爲殭屍態和死亡態。進程完成使命退出後處於殭屍態,此時進程的資源已經被釋放,僅僅保留了task_struct結構(父進程可能使用);而死亡態不僅釋放了所有資源,並且連task_struct結構也釋放了。

    此外,爲了便於記憶,系統給每個狀態分配了一個字母縮寫“RSDTtZXxKWP”,對應關係如下圖所示。



六、進程棧

    linux系統爲每個用戶進程分配了兩個棧:用戶棧和內核棧。當一個進程在用戶空間執行時,系統使用用戶棧;當在內核空間執行時,系統使用內核棧。由於內核棧地址空間的限制,內核棧不會分配很大的空間。此外,內核進程只有內核棧,沒有用戶棧。

    當進程從用戶空間陷入到內核空間時,首先,操作系統在內核棧中記錄用戶棧的當前位置,然後將棧寄存器指向內核棧;內核空間的程序執行完畢後,操作系統根據內核棧中記錄的用戶棧位置,重新將棧寄存器指向用戶棧。由於每次從內核空間中返回時,內核棧肯定已經使用完畢,所以從用戶棧切換到內核棧時,只需要簡單的將棧寄存器指向內核棧頂即可,不需要做什麼特殊處理。


七、進程運行時間

    因爲進程是分時運行的,所以有必要記錄每個進程實際佔用的cpu時間;進程描述符的utimestime成員記錄微秒、秒級的cpu時間。

    start_time成員記錄了創建進程的時間;real_start_time成員記錄了啓動進程的時間。


八、文件資源

    進程描述符中還記錄了和文件相關的信息:文件系統、打開的文件、命名空間等。

    struct fs_struct *fs成員記錄了根目錄和當前目錄信息;struct files_struct *files成員記錄了進程當前打開的文件;struct nsproxy *nsproxy成員記錄了文件系統的命名空間。


九、進程關係

    進程之間存在父子、線程組、進程組等重要的組織關係。

    task_structreal_parent指向父進程、parent指向“養父進程“。父進程是實際創建子進程的進程;而“養父進程”是負責處理子進程消亡的進程,在大多數情況下,父進程就是“養父進程“。但是也有例外,例如,當父進程比子進程提前消亡時,父進程會幫子進程重新尋找一個“養父進程”,通常是進程1children成員是父進程的子進程鏈表;sibling成員是子進程的兄弟進程鏈表。

    task_structgroup_leader成員指向線程組長,thread_group成員是線程組長的線程鏈表。如果,當前線程組只有一個線程,那麼該線程的group_leader成員指向自己,並且thread_group爲空。


十、總結

    本文介紹了進程描述符數據結構,重點描述了進程資源、調度、組織結構等方面的信息。進程資源信息包括文件系統、地址空間、打開的文件等;調度信息包括進程優先級、當前狀態、信號量等;組織結構信息包括進程父子關係、進程組等。


版權聲明:

    原創作品,如非商業性轉載,請註明出處;如商業性轉載出版,請與作者聯繫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章