第三章 進程管理緩存
3.1進程ide
概念:函數
進程:處於執行期的程序。但不只侷限於程序,還包含其餘資源(打開的文件,掛起的信號,內核內部數據,處理器狀態,一個或多個具備內催音社的內存地址空間及一個或多個執行線程,存放全局變量的數據段等)操作系統
內核須要有效又透明地管理全部細節。線程
線程:執行線程的簡稱,是在進程中活動的對象。每一個線程有一個獨立的程序計數器、進程棧和一組進程寄存器。內核調度的對象是線程而不是進程。指針
進程提供兩種虛擬機制:虛擬處理器和虛擬內存。對象
線程之間能夠共享虛擬內存,但每一個都擁有各自的虛擬存儲器。繼承
進程建立:調用fork(),該系統調用經過複製當前進程建立新進程。使用fork()的是父進程。在調用結束時,在返回點這個相同位置,父進程恢復,子進程開始執行。隊列
3.2進程描述符及任務結構進程
內核把進程的列表存放在叫作任務隊列的雙向循環鏈表中。鏈表中的每一項都是task_struct類型,稱爲進程描述符的結構。
該結構內包含了內核管理一個進程所需的全部信息。
分配進程描述符:經過slab分配器分配,爲了對象複用和緩存着色。
進程描述符的存放:進程經過一個惟一的進程標識值(process identification value)標識每一個進程。PID最大默認32768,,就是系統中容許同時存在的進程最大數目。
進程狀態:進程描述符中的state域描述了進程的當前狀態,有五種狀態:運行、可中斷、不可中斷、被跟蹤、中止。
設置當前進程狀態:調整狀態使用set_task_state(task,state)函數。
進程家族樹:系統進程有明顯的繼承關係。全部進程都是init的後代。每一個進程都有父進程,相同父進程的成爲兄弟。
3.3進程建立
Fork()和exec():
Fork()經過拷貝當前進程建立一個子進程。Exec()函數負責都去可執行文件,並將其載入地址空間開始運行。
寫時拷貝:fork()複製全部資源是效率低下的,所以採用寫時拷貝,推遲甚至免除拷貝數據。只有須要寫入的時候,數據才被複制。
Fork():經過clone()系統調用實現fork()。do_fork()調用copy_proceess()函數
調用dup_task_struct()爲新進程建立一個內核棧、thread_info結構和task_stuct結構。這些與當前進程相同,PID也相同。
檢查建立子進程後,用戶多有進程書目沒有超出它分配的資源的限制。
進程描述符的許多成員都要清零或設爲默認,以和父進程區分開。
子進程狀態被設置爲TASK_UNINTERRUPTIBLE,確保不會被投入運行。
調用alloc_pid()爲新進程分配一個有效ID
Copy_process()作掃尾工做,返回一個指向子進程的指針。
Vfork():與fork()的區別就是不考貝父進程頁表項。
3.4線程在Linux中的實現
從內核角度說,Linxu沒有線程概念。全部線程都被看成進程
建立進程:和建立普通進程差很少,只是在調用clone()時須要傳遞一些參數標誌。
內核線程:kernel thread和普通進程的區別在於內核線程沒有獨立地址空間。只在內核空間運行。
3.5進程終結
當一個進程終結,內核必須釋放所佔有的資源,並告知父進程。
靠do_exit()實現:
將tast_struct中的標誌成員設置爲PF_EXITING
調用del_timer_sync()刪除任一內核定時器
調用acct_update_integrals()輸出記帳信息
調用exit_mm()釋放進程佔用的mm_struct。
調用sem_exit()若進程排隊等候IPC,則離開
調用exit_files()和exit_fs()分別遞減文件描述符和文件系統數據的應用計數。
調用exit_notify()向父進程發送信號,給子進程找養父。
do_exit調用schedukle(0切換到新進程。
小結:
本節,咱們學到了操做系統的核心概念——進程。
Linux如何存放和表示進程——用task_struct和thread_info
建立進程——經過fork(),其實是clone()
把新的執行映像裝到地址空間——經過exec()系統調用族
表示進程的層次關係,父進程如何收集其後代信息——經過wait()系統調用族
進程如何消亡——強制或自願調用exit()