第三章讀書筆記——進程管理

第3章 進程管理

進程

進程就是處於執行期的程序(目標碼存放在某種存儲介質上),但進程並不只僅侷限於一段可執行程序代碼

執行線程,簡稱線程,是在進程中活動的對象

在傳統的Linux系統中,一個進程只包含一個線程,但如今的系統中,包含多個線程的多線程程序司空見慣
而在Linux系統中線程只不過是一種特殊的進程罷了
在現代操做系統中,進程提供兩種虛擬機制:linux

  • 虛擬處理器
  • 虛擬內存算法

    在現代Linux內核中,fork()其實是由clone()系統調用實現的。

進程描述符及任務結構

內核把進程的列表存放在叫作任務隊列的雙向循環鏈表中緩存

鏈表中的每項都是類型爲task_struct、稱爲進程描述符的結構,該結構定義在<linux/sched.h>文件中。

進程描述符中包含一個具體進程的全部信息數據結構

分配進程描述符

Linux以經過slab分配器分配task_struct結構,這樣能達到對到對象複用和緩存着色的目的,這樣作是爲了讓那些像x86那樣寄存器較少的硬件體系結結構只要經過棧指針就能夠估算出他的位置
每一個任務的thread_info結構在他的內核棧的尾端分配多線程

進程描述符的存放

內核經過一個惟一的進程標識值或PID來標識每一個進程,內核把每一個進程的PID存放在它們各自的進程描述符中函數

在內核中,訪問任務一般須要得到指向其task_struct的指針,實際上,內核中大部分處理進程程描述符的速度就顯得尤其重要操作系統

進程狀態

進程描述符中state域描述了進程的當前狀態。
五種進程狀態:線程

  • 運行
  • 可中斷
  • 不可中斷
  • 被其餘進程跟蹤的進程
  • 中止指針

    內核須要常常調整某個進程的狀態:set_task_state(task,state)函數

進程上下文

系統調用和異常處理程序是對內核明肯定義的接口
進程只有經過這些接口才能陷入內核執行——對內核的全部訪問都必須經過這些接口
進程家族樹
在Unⅸ系統的進程之間存在—個明顯的繼承關係,在Linux系統中也是如此,全部的進程都是PID爲1的init進程的後代
內核在系統啓動的最後階段啓動init進程
該進程讀取系統的初始化腳本並執行其餘的相關程序,最終完成系統啓動的整個過程對象

進程建立

Linux的fork()使用寫時拷貝頁實現,寫時拷貝是一種能夠推遲甚至免除拷貝數據的技術,內核此時並不複製整個進程地址空間,而是讓父進程和子進程共享同一個拷貝
只有在須要寫入的時候,數據纔會被複制,從而使各個進程擁有各自的拷貝,也就是說資源的複製只有在須要寫入的時候才進行,在此以前,只是以只讀方式共享,這種技術使地址空間上的頁的拷貝被推遲到實際發生寫入的時候才進行在頁根本不會被寫入的狀況下它們就無須複製了

fork()

copy_process()完成的工做:

  • 調用dup_task_struct()爲新進程建立一個內核棧、thread_info結構和task_struct,這些值與當前進程的值相同,此時,子進程和父進程的描述符是徹底相同的
  • 檢查並確保新建立這個子進程後,當前用戶所擁有的進程數目沒有超出給它分配的資源的限制
  • 子進程着手使本身與父進程區別開來,進程描述符內的許多成員都要被清0或設爲初始值
  • 子進程的狀態被設置爲TASK_UNINTERRUPTIBLE,以保證它不會投入運行
  • copy_process()調用copy_flags以更新task_struct的flags成員
  • 調用alloc_pid()爲新進程分配一個有效的PID
  • 根據傳遞給clone()的參數標誌,copy_process()拷貝或共享打開的文件、文件系統信息、信號處理函數、進程地址空間和命名空間等
    在通常狀況下,這些資源會被給定進程的全部線程共享;不然,這些資源對每一個進程是不一樣的,所以被拷貝到這裏

vfork()

Linux實現線程的從內核的角度來講,它並無線程這個概念,Linux把全部的線程都當作進程來實現,內核並無準備特別的調度算法或是定義特別的數據結構來表徵線程,相反,線程僅僅被視爲―個與其餘進程共享某些資源的進程,每一個線程都擁有惟一隸屬於本身task_struct,因此在內核中,它看起來就像是一個普通的進程(只是線程和其餘一些進程共享某些資源,如地址空間)

進程的建立與普通進程的建立相似,只不過在調用clone()時須要傳遞一些參數標誌來指明所須要共享的資源

當一個進程終結時,內核必須釋放它所佔有的資源並把這一不幸告知其父進程

刪除進程描述符:調用release_task函數

孤兒進程形成的進退維谷

若是父進程在子進程以前退出,必須有機制來保證子進程能找到一個新的父親不然這些成爲孤兒的進程就會在退出時永遠處於僵死狀態,白白地耗費內存,前面的部分已經有所暗示於這個問題,解決方法是給子進程在當前線程組內找—個線程做爲父親,若是不行就讓init作它們的父進程 總結 --------- 咱們學到了操做系統中的核心概念——進程,咱們它爲什麼如此重要,以及進程與線程之間的關係,討論了Linux如何存放和表示進程,如何建立進程,如何把新的執行映像裝入到地址空間,如何表示進程的層次關係,父進程又是如何收集其後代的信息以及進程最終如何消亡。

相關文章
相關標籤/搜索