《Linux核心設計與實現》讀書筆記(2)— 進程管理

來源:互聯網
上載者:User

進程管理

1.進程描述符及任務結構

    進程存放在叫做任務隊列(task list)的雙向迴圈鏈表中。鏈表中的每一項包含一個具體進程的所有資訊,類型為task_struct,稱為進程描述符(process descriptor),該結構定義在<linux/sched.h>檔案中。

    Linux通過slab分配器分配task_struct結構,這樣能達到對象複用和緩衝著色(cache coloring)的目的。另一方面,為了避免使用額外的寄存器儲存專門記錄,讓像x86這樣寄存器較少的硬體體繫結構只要通過棧指標就能計算出task_struct的位置,該結構為thread_info,在檔案<asm/thread_info.h>中定義。

 

2.進程狀態

    task_struct中的state描述進程的目前狀態。進程的狀態一共有5種,而進程必然處於其中一種狀態:

    1)TASK_RUNNING(運行)——進程是可執行檔,它或者正在執行,或者在運行隊列中等待執行。這是進程在使用者空間中執行唯一可能的狀態;也可以應用到核心空間中正在執行的進程。

    2)TASK_INTERRUPTIBLE(可中斷)——進程正在睡眠(也就是說它被阻塞)等待某些條件的達成。一旦這些條件達成,核心就會把進程狀態設定為運行,處於此狀態的進程也會因為接收到訊號而提前被喚醒並投入運行。

    3)TASK_UNINTERRUPTIBLE(不可中斷)——除了不會因為接收到訊號而被喚醒從而投入運行外,這個狀態與可打斷狀態相同。這個狀態通常在進程必須在等待時不受幹擾或等待事件很快就會發生時出現。由於處於此狀態的任務對訊號不作響應,所以較之可中斷狀態,使用得較少。

    4)TASK_ZOMBIE(僵死)——該進程已經結束了,但是其父進程還沒有調用wait4()系統調用。為了父進程能夠獲知它的訊息,子進程的進程描述符仍然被保留著。一旦父進程調用了wait4(),進程描述符就會被釋放。

    5)TASK_STOPPED(停止)——進程停止執行,進程沒有投入運行也不能投入運行。通常這種狀態發生在接收到SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU等訊號的時候。此外,在調試期間接收到任何訊號,都會使進程進入這種狀態。

    需要調整進程的狀態,最好使用set_task_state(task, state)函數,在必要的時候,它會設定記憶體屏障來強制其他處理器作重新排序(SMP)。

 

3.進程建立

    在Linux系統中,所有的進程都是PID為1的init進程的後代。核心在系統啟動的最後階段啟動init進程。該進程讀取系統的初始化指令碼(initscript)並執行其他的相關程式,最終完成系統啟動的整個進程。

    Linux提供兩個函數去處理進程的建立和執行:fork()和exec()。首先,fork()通過拷貝當前進程建立一個子進程。子進程與父進程的區別僅僅在於PID(每個進程唯一),PPID(父進程的PID)和某些資源和統計量(例如掛起的訊號)。exec()函數負責讀取可執行檔並將其載入地址空間開始運行。

    fork()使用寫時拷貝(copy-on-write)頁實現。核心在fork進程時不複製整個進程地址空間,讓父進程和子進程共用同一個拷貝,當需要寫入時,資料才會被複製,使各進程擁有自己的拷貝。在頁根本不會被寫入的情況下(fork()後立即exec()),fork的實際開銷只有複製父進程的頁表以及給子進程建立唯一的task_struct。

 

4.線程的實現

    從Linux核心的角度來說,它並沒有線程這個概念。Linux把所有的線程都當作進程來實現,核心並沒有準備特別的調度演算法或者定義特別的資料結構來表徵線程。相反,每個線程都擁有唯一隸屬於自己的task_struct,它看起來就像是一個普通的進程,只是該進程和其他一些進程共用某些資源,如地址空間。

 

5.進程終結

    進程在運行結束,或接受到它既不能處理也不能忽略的訊號,或異常時,都會被終結。此時,依靠do_exit()(在kernel/exit.c檔案中)把與進程相關聯的所有資源都被釋放掉(假設進程是這些資源的唯一使用者)。進程不可運行(實際上也沒有地址空間讓它運行)並處於TASK_ZOMBIE狀態。它佔用的所有資源就是核心棧、thread_info和task_struct。在父進程獲得已終結的子進程的資訊後,或者通知核心它並不關注那些資訊後,子進程的task_struct才被釋放。

    如果父進程在子進程之前退出,必須有機制保證子進程能找到一個新的父類,否則的話這些成為孤兒的進程就會在退出時永遠處於僵死狀態,白白的耗費記憶體。解決方案是給子進程在當前線程組內找一個線程作為父親,如果不行,就讓init做它們的父進程。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.