Linux學習記錄之進程(一)

進程是Unix操作系統的最重要的抽象之一,它是處於執行期的程序,但是它不僅僅包括代碼,還包括相關的文件,掛起信號等資源。線程是進程活動的對象,每個線程都有一個程序計數器,進程棧和一組進程計數器。Linux中線程是進程的一種特例。

進程提供兩種虛擬機制,虛擬處理器和虛擬內存。

Linux系統中通過fork()系統調用來產生新的進程,產生的方式是複製當期的進程來產生新進程,所以調用fork()的進程稱爲父進程,新產生的進程被稱爲子進程。Linux系統中fork()是調用clone()這個系統調用。

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

內核進程放在一個角task_list的雙向循環鏈表裏,每一個節點都是一個task_struct,稱爲進程描述符,該結構定義在<linux/sched.h>中。task_struct包含了描述一個進程的完整信息。

1.1分配進程描述符

Linux通過slab分配器來分配task_struct結構,這樣能達到對象複用和緩存着色,(通過預分配和重複使用task_struct,可以避免動態分配和釋放所帶來的資源消耗,從而使得進程創建的速度較快)。現在不需要專門的寄存器,只需要在棧底放一個thread_info,這個struct可以方便快速計算出task_struct所在位置。

1.2進程描述符的存放

Linux爲每個進程分配了一個PID,實際是個int類型,其默認最大值爲32768,內核把每個進程的PID放在進程描述符中。這個值越小,轉一圈的時間就越快。如果需要,可以修改/proc/sys/kernel/pid_max裏的內容來修改最大值。

1.3進程的狀態


1.4設置狀態

內存需要經常設置進程的狀態,這時候可以調用set_task_state(tast,state)函數來設置。

1.5進程上下文

在用戶態執行的進程在系統調用和發送異常時會進入內核態,這時內核就成爲代表程序運行的的進程上下文。

1.6進程家族樹

Linux進程具備繼承關係,所有的繼承都是PID爲1的init進程的後代。內核在系統啓動的最後節點啓動init進程,該進程讀取初始化腳本,並執行其他的相關程序,最終完成系統啓動的整個過程。每個task_struct都包含一個parent節點的指針和一個children的鏈表。

2進程創建

許多其他的操作系統都提供了產生集成的機制,首先在地址空間裏創建進程,讀入可執行文件,最後開始執行。Unix採用了與衆不同的實現方式,它把上述步驟分解到兩個單獨的函數中去執行:fork()和exec()函數族。首先,fork()通過拷貝當期進程創建一個子進程。子進程與父進程的區別僅僅在於PID、PPD和默寫資源和統計裏。exec()函數負責拂去可執行文件並將其載入地址空間開始運行。

2.1寫時拷貝

Linux的fork()使用寫時拷貝頁實現。寫時拷貝可以推遲甚至免除拷貝數據。內核此時不復制整個進程的地址空間,二是讓父進程和子進程共享一個拷貝。還有在需要寫入的時候,數據纔會被複制,從而使各個進程擁有各自的拷貝。而一般情況下,fork()之後立即調用exec(),它們就無需複製了,fork()的實際開銷就是複製父進程的頁表及自己喫創建唯一的基礎描述符。在一般情況下,進程創建後都會馬上運行一個可執行文件,這種優化可以避免拷貝大量根本就不會被使用的數據。

2..2 fork()

fork()通過clone()系統調用實現,clone()調用do_fork(),do_fork完成大部分工作,它定義在kernel/fork.c文件中。該函數調用copy_process()函數,然後讓進城開始執行。copy_process()函數完成的工作:

1、調用dup_task_struct()爲新進程創建一個內核棧,threa_info結構和task_struct,這些值與當期進程值形同。連進程描述符也是完全相同。

2、檢測新創建的這個子進程後,當期用戶所擁有的進程數目有沒有超過最大值。

3、現在,進程着手是自己與父進程區別開。進程描述符內的許多成員都要被請0或設置爲初始值。進程描述符的成員值不是繼承而來的,而主要是統計信息。進程描述符中大多數數據都是共享的。

4、接下來,子進程的狀態被設置爲TASK_UNINTERRUPTEBLE以保證她不會投入運行。

5、copy_process()調用copy_flags()以更新task_struct的flags成員。表面進程是否擁有超級用戶權限的PF_SUPERRIV標誌被請0.表明進程還沒有調用exec()函數的PF_FORKNOEXEC標誌被設置。

6、調用get_pid()爲新進場獲取一個有效的PID。

7、根據傳遞給clone()的參數標誌,copy_process()拷貝或共享打開的文件、文件系統信息、信號處理函數、進程地址空間和命名空間等。在一般情況下,這些資源會被給定的進程的左右進程共享;否則,這些資源對每個進程是不同的,因此被拷貝到這裏。

8、讓父進程和子進程評分剩餘的時間片。

9、最後,copy_process()函數作搜啊爲歐諾工作,並返回一個指向子進程的指針。

最後回到do_fork()函數。




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