2020-01-17 進程管理

2.進程管理

進程是Unix操作系統(tǒng)最基本的抽象之一。
定義: 進程就是處于執(zhí)行期的程序胰耗,以及它所包含的資源的總稱

包含:
可執(zhí)行程序代碼 (Unix稱為代碼段 Text section)
存放全局變量的數(shù)據(jù)段 Data section
打開文件侥蒙、掛起的信號
地址空間一個或多個執(zhí)行線程 threads of execution

另一個名字:任務(wù)task峰弹,內(nèi)核通常把進程也叫做任務(wù)

2.1 進程描述符及任務(wù)隊列

                +-------------------------+
          +-->  |    struct task_struct   |
          +-----+-------------------+-----+
      +-> |    struct task_struct   |     |
      +---+---------------------+---+     |
+-->  |    struct task_struct   |   |     |
+-----+-------------------+-----+   |     |
|    struct task_struct   |     |   |     |
+-------------------------+     |   |     |
|  unsigned long state;   |     |   |     |
|  int prio;              |     |   |     |
|  unsigned long policy   |     |   | <---+
|  struct task_struct *parent   |   |   
|  struct list_head tasks;|     |   | 
|  pid_t pid;             |     |<--+ 
|  ...                    |     |   
|                         |     | 
|     進程描述符          | <---+
|                         |     
+-------------------------+     

|                  任務(wù)鏈表                  |
|                                            |
+--------------------------------------------+

2.1.1 分配進程描述符

Linux通過slab分配器分配task_struct 結(jié)構(gòu)(預(yù)先分配和重復(fù)使用task_struct赘理,避免動態(tài)分配的資源消耗座韵,所以進程創(chuàng)建迅速)

             進程內(nèi)核棧
+------------------------+ 最高的內(nèi)存地址
|                        |
|                        |
|                        |
+------------------------+ 棧指針
|                        |
|                        |
+------------------------+
|                        |
|                        |
| struct thread_struct   |
+----+-------------------+ 最低的內(nèi)存地址   current_thread_info()-
     |
     | thread info 有一個指向進程描述符的指針
     |
     |
     v-----------------> 進程的task_struct結(jié)構(gòu)

進程描述符及內(nèi)核棧

struct thread_info {
    struct task_struct *task;
    struct exec_domain *exec_domain;
    unsigned long flags;
    _u32 cpu
    _s32 preempt_count;
    mm_segment_t addr_limit;
    u8 supervisor_stack[0];
}

2.1.2 進程描述符的存放

PID pid_t

內(nèi)核中,訪問任務(wù)通常需要獲得指向其task_struct指針腹备,內(nèi)核大部分處理進程的代碼都是直接通過task_struct進行的

x86 寄存器并不富余衬潦,只能在內(nèi)核在的尾端創(chuàng)建thread_info結(jié)構(gòu),通過計算偏移間接地查找task_struct

2.1.3 進程狀態(tài)

   創(chuàng)建新進程                       任務(wù)被終止
+------------------+              +------------------+
|                  |              |                  |
|   fork()         |              | TASK_ZOMBIE      |
|   a new task     |              |                  |
+-----+------------+              +------------------+
      |
      |                                  ^
      |           調(diào)度程序?qū)⑷蝿?wù)投入運行 |
      |           schedule()函數(shù)調(diào)用     |
      |           context_switch()       |
      |      +---------------------+     |  任務(wù)通過do_exit()函數(shù)退出
      v      |                     |     |
             |                     v     |
 +-----------+------+            +-+-----+----------+
 | TASK_RUNNING     |            | TASK_RUNNING     |
 |                  |            |                  |  正在運行
 +------------------+            +---+-------+------+
   準備就緒      ^                   |       |
   還未投入運行  |                   |       |
        ^        |                   |       |
        |        +-----<-------------+       |
        |         任務(wù)被優(yōu)先級更高           |
        |         的任務(wù)搶占                 |
        |                                    |
        |                                    |為了等待特定事件
        |                                    |任務(wù)在等待隊列上睡眠
        |                                    |
        |        +---------------------+     |
        |        |TASK_INTERRUPTIBLE   |     |
        +--------+or                   |     |
                 |TASK_UNINTERRUPTIBLE | <---+
等待的事件發(fā)生后 |                     |
任務(wù)被喚醒       +---------------------+
重新進入運行隊列              等待

進程上下文

當一個程序執(zhí)行了系統(tǒng)調(diào)用或者觸發(fā)了某個異常植酥,它就陷入了內(nèi)核空間
此時,我們稱內(nèi)核"代表進程執(zhí)行"弦牡,并處于進程上下文中友驮。
除非在此間隙有更高優(yōu)先級的進程需要執(zhí)行并由調(diào)度器做出了調(diào)整,否則在內(nèi)核退出時候驾锰,程序恢復(fù)在用戶空間繼續(xù)執(zhí)行
進程只有通過系統(tǒng)接口(系統(tǒng)調(diào)用和異常) 才能陷入內(nèi)核

                    +--------+      +--------+
                    |        |      |        |
         +----------+parent  | <----+parent  |
         |          |children+----> |children|
         v          +--------+      +--------+
    +--------+      +--------+      +--------+
    |        |      |        |      |        |
    | init   | <----+parent  | <----+parent  |
    |        |      |children+----> |children|
    +--------+      +--------+      +--------+

2.2進程創(chuàng)建

fork() 復(fù)制當前進程創(chuàng)建子進程
exec() 讀取可執(zhí)行文件卸留,并將其載入地址空間開始運行

linux 的fork,并不會立即復(fù)制整個進程地址空間椭豫,而是讓父進程和子進程共享一個拷貝
在需要寫入的時候耻瑟,數(shù)據(jù)才會被復(fù)制

而 fork 之后立即調(diào)用exec() 旨指,他們就無需復(fù)制,可以避免大量復(fù)制父進程數(shù)據(jù)

普通fork()

clone(SIGCHLD,0);

vfork()

clone(CLONE_VFORK | CLONE_VM | CLONE_SIGHAND, 0);

2.3 線程在Linux 中的實現(xiàn)

線程提供了在同一程序內(nèi)共享內(nèi)存地址空間運行的一組線程
線程可以共享打開的文件和其他資源喳整,線程機制支持并發(fā)程序設(shè)計技術(shù)谆构,在多處理器上,它能保證真正的并行處理

linux實現(xiàn)比較獨特框都。內(nèi)核的角度來說搬素,他們有線程的該你那,把所有的線程都當做進程來實現(xiàn)魏保。
線程僅僅被視為一個使用某些共享資源的進程熬尺。
每個線程都擁有唯一隸屬于自己的task_struct,在內(nèi)核中谓罗,它看起來像是一個普通的進程
該進程和其他一些進程共享某些資源粱哼,比如地址空間

線程的創(chuàng)建和普通進程的創(chuàng)建類似,只不過在調(diào)用clone()時候需要傳遞一些參數(shù)標志來指明需要共享的資源

clone(CLONE_VM | COLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0);

共享地址檩咱,共享文件資源揭措,共享文件描述符,共享信號

參數(shù)標記 含義
CLONE_CLEARTID 清除TID
CLONE_DETACHED 父進程不需要子進程退出時發(fā)送SIGCHLD
CLONE_FILES 父進程共享打開的文件
CLONE_FS 父子進程共享文件系統(tǒng)信息
CLONE_IDLETASK 將PID設(shè)置為0(只提供idle進程使用)
CLONE_NEWNS 為子進程創(chuàng)建新的命名空間
CLONE_PARENT 指定子進程與父進程擁有同一個父進程
CLONE_PTRACE 繼續(xù)調(diào)試子進程
CLONE_SETTID 將TID回寫到用戶空間
CLONE_SETTLS 為子進程創(chuàng)建新的TLS
CLONE_SIGHAND 父子進程共享信號處理函數(shù)
CLONE_SYSVSEM 父子進程共享System V SEM_UNDO 語義
CLONE_THREAD 父子進程放入相同的線程組
CLONE_VFORK 調(diào)用vfork(),所以父進程準備睡眠等待子進程將其喚醒
CLONE_VM 父子進程共享地址空間

2.3.1 內(nèi)核線程

內(nèi)核需要在后臺執(zhí)行一些操作税手,這種任務(wù)可以通過內(nèi)核線程 kernel thread完成
獨立運行在內(nèi)核空間的標準進程
內(nèi)核線程和普通進的區(qū)別在于內(nèi)核線程沒有獨立的地址空間 實際上他的 mm 指針被設(shè)置NULL

2.4 進程終結(jié)

所有進程的終止都是由do_exit()函數(shù)來處理的蜂筹,這個函數(shù)從內(nèi)核數(shù)據(jù)結(jié)構(gòu)中刪除對終止進程的大部分引用

  • 把進程task_struct的flag字段設(shè)置為PF_EXITING標志,以表示進程正在被刪除芦倒。
  • 如果BSD的進程記賬功能是開啟的艺挪,要調(diào)用accp_process() 來輸出記賬信息
  • 調(diào)用_exit_mm()函數(shù)放棄進程占用的mm_struct,如果沒有別的進程使用它們(如果沒有別的進程使用它們兵扬,也就是說麻裳,它們沒有被共享),就徹底釋放它們
  • 如果需要器钟,通過函數(shù)del_timer_sync()從動態(tài)定時器隊列中刪除進程描述符津坑。
  • 分別調(diào)用exit_mm()、exit_sem()傲霸、__exit_files()疆瑰、__exit_fs()、exit_namespace()和exit_thread()函數(shù)從進程描述符中分離出與分頁昙啄、信號量穆役、文件系統(tǒng)、打開文件描述符梳凛、命名空間以及I/O權(quán)限位圖相關(guān)的數(shù)據(jù)結(jié)構(gòu)耿币。如果沒有其它進程共享這些數(shù)據(jù)結(jié)構(gòu),那么這些函數(shù)還刪除所有這些數(shù)據(jù)結(jié)構(gòu)中韧拒。
  • 如果實現(xiàn)了被殺死進程的執(zhí)行域和可執(zhí)行格式的內(nèi)核函數(shù)包含在內(nèi)核模塊中淹接,則函數(shù)遞減它們的使用計數(shù)器十性。
  • 把進程描述符的exit_code字段設(shè)置成進程的終止代號,這個值要么是_exit()或exit_group()系統(tǒng)調(diào)用參數(shù)塑悼,要么是由內(nèi)核提供的一個錯誤代碼劲适。
  • 調(diào)用exit_notify()函數(shù),向父進程發(fā)送信號,將子進程的父進程重新設(shè)置為線程組中的其他線程或init進程, 狀態(tài) TASK_ZOMBIE
  • 調(diào)用 schedule()切換到其他進程

具體exit_notify

a. 更新父進程和子進程的親屬關(guān)系拢肆。如果同一線程組中有正在運行的進程减响,就讓終止進程所創(chuàng)建的所有子進程都變成同一線程組中另外一個進程的子進程,否則讓它們成為init的子進程

b. 檢查被終止進程其進程描述符的exit_signal字段是否不等于-1郭怪,并檢查進程是否是其所屬進程組的最后一個成員支示。在這種情況下,函數(shù)通過給正被終止進程的父進程發(fā)送一個信號鄙才,以通知父進程子進程死亡颂鸿。

c. 否則,也就是exit_signal字段等于-1攒庵,或者線程組中還有其它進程嘴纺,那么只要進程正在被跟蹤,就向父進程發(fā)送一個SIGCHLD信號浓冒。

d. 如果進程描述符的exit_signal字段等于-1栽渴,而且進程沒有被跟蹤,就把進程描述符的exit_state字段置為EXIT_DEAD稳懒,然后調(diào)用release_task()回收進程的其它數(shù)據(jù)結(jié)構(gòu)占用的內(nèi)存闲擦,并遞減進程描述符的使用計數(shù)器,以使進程描述符本身正好不會被釋放场梆。

e. 否則墅冷,如果進程描述符的exit_signal字段不等于-1,或進程正在被跟蹤或油,就把exit_state字段置為EXIT_ZOMBIE寞忿。

f. 把進程描述符的flags字段設(shè)置為PF_DEAD標志。

調(diào)用schedule()函數(shù)選擇一個新進程運行顶岸。調(diào)度程序忽略處于EXIT_ZOMBIE狀態(tài)的進程腔彰,所以這種進程正好在schedule()中的宏switch_to被調(diào)用之后停止執(zhí)行。

2.4.1 刪除進程描述符

調(diào)用 do_exit()之后辖佣,盡管線程已經(jīng)僵尸不能運行萍桌,但是系統(tǒng)還保留他的進程描述符
父進程獲得已終結(jié)的子進程的信息后,子進程task_struct結(jié)構(gòu)才能釋放

wait() 這一組函數(shù)都是通過唯一的一個系統(tǒng)調(diào)用wait4()實現(xiàn)的凌简,他的標準動作是掛起調(diào)用它的進程,直到其中的一個子進程退出恃逻,此時函數(shù)會返回該子進程PID雏搂。此外藕施,調(diào)用該函數(shù)時提供的指針會包含子函數(shù)退出是的退出代碼

release_task()

  • free_uid() 減少該進程擁有者的進程使用計數(shù)。

linux用一個單用戶告訴緩存統(tǒng)計和記錄每個用戶占用的進程數(shù)目凸郑、文件數(shù)目裳食。如果這些數(shù)目都為0,表明這個用戶沒有使用任何進程和文件芙沥,那么這塊緩存可以銷毀

  • unhash_process() 從pidhash上刪除該進程诲祸,同時也要從task_list中刪除該進程
  • 如果這個進程正在被ptrace追蹤,將跟蹤進程的父進程重設(shè)為其最初的父進程并將它從ptrace list上刪除
  • put_task_struct()釋放進程內(nèi)核棧和thread_info結(jié)構(gòu)所占用的頁而昨,并釋放task_struct所占用的slab高速緩存

2.4.2 孤兒進程

如果父進程在子進程之前推出救氯,必須有機制來保證子進程能找到一個新的父親,否則這些孤兒的進程就會在推出時候永遠處于僵尸狀態(tài)歌憨,白白消耗內(nèi)存着憨。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市务嫡,隨后出現(xiàn)的幾起案子甲抖,更是在濱河造成了極大的恐慌,老刑警劉巖心铃,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件准谚,死亡現(xiàn)場離奇詭異,居然都是意外死亡去扣,警方通過查閱死者的電腦和手機柱衔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來厅篓,“玉大人秀存,你說我怎么就攤上這事∮鸬” “怎么了或链?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長档押。 經(jīng)常有香客問我澳盐,道長,這世上最難降的妖魔是什么令宿? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任叼耙,我火速辦了婚禮,結(jié)果婚禮上粒没,老公的妹妹穿的比我還像新娘筛婉。我一直安慰自己,他們只是感情好癞松,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布爽撒。 她就那樣靜靜地躺著入蛆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪硕勿。 梳的紋絲不亂的頭發(fā)上哨毁,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機與錄音源武,去河邊找鬼扼褪。 笑死,一個胖子當著我的面吹牛粱栖,可吹牛的內(nèi)容都是我干的话浇。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼查排,長吁一口氣:“原來是場噩夢啊……” “哼凳枝!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起跋核,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤岖瑰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后砂代,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蹋订,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年刻伊,在試婚紗的時候發(fā)現(xiàn)自己被綠了露戒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡捶箱,死狀恐怖智什,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情丁屎,我是刑警寧澤荠锭,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站晨川,受9級特大地震影響证九,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜共虑,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一愧怜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧妈拌,春花似錦拥坛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽疾党。三九已至,卻和暖如春惨奕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背竭钝。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工梨撞, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人香罐。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓卧波,卻偏偏與公主長得像,于是被迫代替她去往敵國和親庇茫。 傳聞我的和親對象是個殘疾皇子港粱,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容