進程可以產生一個或多個子進程,但最終都要死亡。進程沒沒有性別差異—每個進程都只有一個父親。
從內核觀點來看,擔當分配系統資源(CPU時間,內存等)的實體。
早期的進程:當一個進程創建時,它幾乎與父進程相同。它接收父進程地址空間的(邏輯)拷貝,並從進程創建系統調用下一條指令開始執行與父進程相同的代碼。
現代的進程:多線程應用程序—擁有很對獨立執行流的用戶程序共享程序的大部分數據結構。現在,大部分多線程應用程序都是用pthread(POSIX thread)庫的標準函數集編寫的。
子進程
調用了fork()函數會發生什麼?
fork()函數啓動了一個新的進程,這個進程幾乎是當前進程的一個拷貝。
對於父進程來說,fork函數返回了子進程的進程號。
而對於子進程來說,fork函數則返回0.
fork複製只是邏輯上的複製,物理上的都還在共享,由相應的內存描述符組成。
進程創建
Unix操作系統緊緊依賴進程創建來滿足用戶的需求。例如,只要一個用戶輸入一條命令,shell進程就創建一個新進程,新進程執行shell的另一個拷貝。
傳統的Unix以統一的方式對待所有進程:子進程複製父進程所擁有的資源,這種方法使得進程創建慢效率低,因爲子進程需要拷貝父進程的整個地址空間。
現代Unix內核通過引入三種不同機制來解決這個問題:
- 寫時複製技術允許父子進程讀相同的物理頁。只要兩者中一個試圖寫一個物理頁,內核就把這個頁的內容拷貝到一個新的物理頁中,並把這個物理頁分配給正在寫的進程。
- 輕量級進程允許父子進程共享每進程在內核的很多數據結構,如頁表(也就是整個用戶態地址空間),打開文件表及信號處理。
- vfork()系統創建的進程能共享父進程的內存地址空間。
clone,fork,vfork
- Linux中,輕量級進程由clone()函數創建的
這個函數使用下列參數:- fn:指定一個由新進程執行的函數。當這個函數返回時,子進程終止。函數返回一個整數,表示子進程的退出代碼。
- arg:指向傳遞給fn()函數的數據
- flags:各種各樣的信息
- child_stack:表示把用戶態堆棧指針賦給子進程的esp寄存器。調用進程應該總是爲子進程分配新的堆棧。
- tls:表示線程局部存儲段(TLS)數據結構的地址
- ptid:表示父進程的用戶態變量地址,該父進程具有與輕量級進程相同的PID。
- ctid:表示新輕量級進程的用戶態變量地址,該進程具有這一類進程的PID。
- 傳統的fork()系統調用在Linux中是用clone()來實現的
- 前面描述的vfork()系統調用在Linux也是用clone()實現的。
- do_fork()函數負責處理clone(),fork()和vfork()系統調用
exec()函數族
系統調用execve()對當前進程進行切換,替換爲一個指定的程序,其參數包括文件名,參數列表以及環境變量。
一旦一個進程調用了exec類函數,它本身就死亡了,系統把代碼替換爲程序的代碼,廢棄原有的數據段和堆棧段,並分配新的,進程號不變。
如果我的程序想啓動另一程序的執行但是自己仍然想繼續運行的話怎麼辦?那就是結合fork和exec的使用。