進程就是處於執行期的程序(目標碼存放在某種存儲介質上)。但進程並不只僅侷限於一段可執行程序代碼( Unix稱其爲代碼段,text section)。一般進程還要包含其餘資源,像打開的文件,掛起的信號,內核內部數據,處理器狀態,一個或多個具備內存映射的內存地址空間及一個或多個執行線程(threa do fexecution),固然還包括用來存放全局變量的數據段等。linux
程序自己並非進程,進程是處於執行期的程序以及相關的資源的總稱。實際上,徹底可能存在兩個或多個不一樣的進程執行的是同一個程序。而且兩個或兩個以上並存的進程還能夠共享許多諸如打開的文件、地址空間之類的資源。編程
一般,建立新的進程都是爲了當即執行新的、不一樣的程序,而接着調用exec。這組函數就能夠建立新的地址空間,並把新的程序載入其中。數組
最終,程序經過exi的系統調用退出執行。這個函數會終結進程並將其佔用的資源釋放掉。父進程能夠經過wait4()9系統調用查詢子進程是否終結,這其實使得進程擁有了等待特定進程執行完畢的能力。進程退出執行後被設置爲僵死狀態,直到它的父進程調用wait()或waitpid()爲止。併發
進程描述符中包含的數據能完整地描述一個正在執行的程序:它打開的文件,進程的地址空間,掛起的信號,進程的狀態,還有其餘更多信息(見下圖)
函數
每一個任務的thread_info 結構在色的內核栓的尾端分配。結構中task 域中存放的是指向該任務實際task_struct 的指針。spa
Unix 的進程建立很特別。許多其餘的操做系統都提供了產生(spawn)進程的機制,首先在新的地址空間裏建立進程,讀入可執行文件,最後開始執行。Unix 採用了不同凡響的實現方式,它把上述步驟分解到兩個單獨的函數中去執行: forkO 和exec()首先,fork()經過拷貝當前進程建立一個子進程。子進程與父進程的區別僅僅在於PID(每一個進程惟一)、PPID(父進程的進程號,子進程將其設置爲被拷貝進程的PID)和某些資源和統計量(例如,掛起的信號,它沒有必要被繼承〉。exec()函數負責讀取可執行文件並將其載入地址空間開始運行。把這兩個函數組合起來使用的效果跟其餘系統使用的單一函數的效果類似。操作系統
Linux 的fork()使用寫時拷貝(copy-on-write)頁實現。寫時拷貝是一種能夠推遲甚至免除拷貝數據的技術。內核此時並不複製整個進程地址空間, 而是讓父進程和子進程共享同-個拷貝.只有在須要寫入的時候,數據纔會被複制,從而使各個進程擁有各自的拷貝。也就是說,資源的複製只有在須要寫入的時候才進行,在此以前,只是以只讀方式共享。線程
Linux 經過clone()系統調用實現fork()。這個調用經過一系列的參數標誌來指明父、子進程須要共享的資源。
do_fork 完成了建立中的大部分工做,它的定義在kemeVfork.c 文件中。該函數調用copy_
process()函數,而後讓進程開始運行。copy_process()函數完成的工做頗有意思:設計
除了不拷貝父進程的頁表項外,vfork()系統調用和fork()的功能相同。3d
錢程機制是現代編程技術中經常使用的一種抽象概念. 該機制提供了在同一程序內共享內存地址
空間運行的一組線程。這些線程還能夠共享打開的文件和其餘資源.線程機制支持併發程序設計技術(concurrentprogramming),在多處理器系統上,它也能保證真正的井行處理( parallelism )。Linux實現線程的機制很是獨特。從內核的角度來講,它並無線程這個概念。Linux 把所
有的錢程都當作進程來實現。
內核常常須要在後臺執行一些操做。這種任務能夠經過內核線程( kernel thread)完成————獨立運行在內核空間的標準進程。內核線程和普通的進程闊的區別在於內核線程沒有獨立的地址空間(實際上指向地址空間的mm指針被設置爲NULL ).它們只在內核空間運行,歷來不切換到用戶空間去.內核進程和普通進程同樣,能夠被調度,也能夠被搶佔.
雖然讓人傷感,但進程終歸是要終結的(說得好像真的很傷感同樣)。當一個進程終結時,內核必須釋放它所佔有的資掠並把這一不幸告知其父進程。
若是父進程在子進程以前退出,必須有機制來保證子進程能找到一個新的父親,不然這些成爲孤兒的進程就會在退出時永遠處於僵死狀態,白白地豔費內存。