自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Linux是如何創(chuàng)建進程的?為什么說Linux與其他操作系統(tǒng)不同?

系統(tǒng) Linux 新聞
前面兩節(jié)簡要地從C語言源代碼層面討論了Linux系統(tǒng)中進程的基本概念,我們知道了Linux內核如何描述和記錄進程的資源,以及進程的五種基本狀態(tài)和進程的家族樹。事實上,就進程管理而言,Linux還是有一些獨特之處的。

前面兩節(jié)簡要地從C語言源代碼層面討論了Linux系統(tǒng)中進程的基本概念,我們知道了Linux內核如何描述和記錄進程的資源,以及進程的五種基本狀態(tài)和進程的家族樹。事實上,就進程管理而言,Linux還是有一些獨特之處的。

[[272837]]

Linux 系統(tǒng)中的進程創(chuàng)建

許多操作系統(tǒng)都提供了專門的進程產生機制,比較典型的過程是:首先在內存新的地址空間里創(chuàng)建進程,然后讀取可執(zhí)行程序,裝載到內存中執(zhí)行。

Linux 系統(tǒng)創(chuàng)建線程并未使用上述經典過程,而是將創(chuàng)建過程拆分到兩組獨立的函數中執(zhí)行:fork() 函數和 exec() 函數族。

基本流程是這樣的:首先,fork() 函數拷貝當前進程創(chuàng)建子進程。產生的子進程與父進程的區(qū)別僅在與 PID 與 PPID 以及某些資源和統(tǒng)計量,例如掛起的信號等。準備好進程運行的地址空間后,exec() 函數族負責讀取可執(zhí)行程序,并將其加載到相應的位置開始執(zhí)行。

Linux 系統(tǒng)創(chuàng)建進程使用的這兩組函數效果與其他操作系統(tǒng)的經典進程創(chuàng)建方式效果是相似的,可能有讀者會覺得這么做會讓進程創(chuàng)建過于繁瑣,其實不是的,Linux 這么做的其中一個原因是為了提高代碼的復用率,這得益于 Linux 高度概括的抽象,無需再額外設計一套機制用于創(chuàng)建進程。

“寫時拷貝”

早期 Linux 中的 fork() 函數直接把父進程的所有資源賦值給創(chuàng)建出的子進程,這樣的機制自然是簡單的,但是效率卻比較低下。

原因是顯而易見的:子進程并不一定要使用父進程的資源,或者子進程可能僅需以只讀的方式訪問父進程的資源,這時“拷貝一份資源”就純屬多余的開銷了。

針對這樣的問題,Linux 后續(xù)版本中的 fork() 函數開始采用“寫時拷貝”機制。寫時拷貝技術可以將拷貝需求延遲,甚至免除拷貝,減小開銷。

具體來說就是,Linux 在調用 fork() 創(chuàng)建子進程時,并不著急拷貝整個進程地址空間,而是暫時讓父子進程以只讀的方式共享同一個拷貝。拷貝動作只在子進程需要寫入時才會發(fā)生,以確保各個進程有自己獨立的內存空間。

如果子進程用不到或者只需要讀取共享空間數據,那么拷貝動作就被省去了,Linux 就減小了開銷。例如,系統(tǒng)調用 fork() 后立即調用 exec(),此時 exec() 會加載新的映像覆蓋 fork() 的地址空間,拷貝動作完全可以省去。

事實上,fork() 函數的實際開銷就是復制父進程的頁表以及給子進程創(chuàng)建唯一的進程描述符。在大多數情況下,Linux 創(chuàng)建進程后都會馬上運行新的可執(zhí)行程序,因此“寫時拷貝”機制可以避免相當多的數據拷貝。創(chuàng)建進程速度快是 Linux 系統(tǒng)的一個特征,因此“寫時拷貝”是一種相當重要的優(yōu)化。

創(chuàng)建進程時,內存地址空間里常常包含數十 MB 的數據,如果每創(chuàng)建一次進程,就拷貝一次數據,開銷顯然是非常大的。

fork() 函數

Linux 中的 fork() 函數其實是基于 clone() 實現的,clone() 函數可以通過一系列參數標志指定父子進程需要共享的資源,在 Linux 中輸入 man 命令可以查看 clone() 函數的C語言原型:

Linux是如何創(chuàng)建進程的?為什么說Linux與其他操作系統(tǒng)不同?

clone() 函數的C語言原型

以及相關的參數標志:

Linux是如何創(chuàng)建進程的?為什么說Linux與其他操作系統(tǒng)不同?

相關的參數標志

在Linux中,fork() 函數最終調用了 do_fork() 函數,它的C語言代碼如下,請看(do_fork() 函數的C語言代碼比較長,下面面只列出了一部分):

Linux是如何創(chuàng)建進程的?為什么說Linux與其他操作系統(tǒng)不同?

do_fork() 函數的C語言代碼

do_fork() 函數完成了進程創(chuàng)建的大部分工作,從相關的C語言源代碼可以看出,它調用了 copy_process() 函數,copy_process() 函數的C語言源代碼如下,請看:

Linux是如何創(chuàng)建進程的?為什么說Linux與其他操作系統(tǒng)不同?

copy_process() 函數的C語言源代碼

copy_process() 函數的代碼也是比較長的,在我手上的Linux系統(tǒng)中,達到了近 400 行,不過代碼的整體邏輯是清晰的:

(1)copy_process() 函數首先檢查了一些標志位,接著調用 dup_task_struct() 函數為新進程創(chuàng)建內核棧,以及上一節(jié)提到的 thread_info 和 task_struct 結構:

Linux是如何創(chuàng)建進程的?為什么說Linux與其他操作系統(tǒng)不同?

調用 dup_task_struct() 函數為新進程創(chuàng)建內核棧

創(chuàng)建后,接下來的 arch_dup_task_struct() 函數會將 orig 結構拷貝給新創(chuàng)建的結構,查看相關C語言代碼,這一過程是清晰的:

Linux是如何創(chuàng)建進程的?為什么說Linux與其他操作系統(tǒng)不同?

拷貝給新創(chuàng)建的結構

此時子進程和父進程的描述符是完全相同的。

(2)接下來,需要檢查一些標志位和統(tǒng)計信息,相關的C語言代碼如下,請看:

Linux是如何創(chuàng)建進程的?為什么說Linux與其他操作系統(tǒng)不同?

檢查一些標志位和統(tǒng)計信息

(3)將一些統(tǒng)計量清零,以及初始化一些區(qū)別成員,此時雖然新進程的 task_struct 結構體大多成員未被修改,但是父子進程已經有所區(qū)別。這一過程的相關C語言代碼片段如下,請看:

Linux是如何創(chuàng)建進程的?為什么說Linux與其他操作系統(tǒng)不同?

將一些統(tǒng)計量清零,以及初始化一些區(qū)別成員

(4)將新創(chuàng)建的子進程狀態(tài)設置為 TASK_UNINTERRUUPTIBLE,確保其暫時不會被投入運行,這一過程的C語言代碼相對簡單。

(5)調用 alloc_pid() 函數為新進程分配一個獨一無二的 pid,相關C語言代碼如下,請看:

Linux是如何創(chuàng)建進程的?為什么說Linux與其他操作系統(tǒng)不同?

為新進程分配一個獨一無二的 pid

(6)根據 clone() 函數的參數標志位,拷貝或共享已經打開的文件、文件系統(tǒng)、信號處理函數、進程地址空間等資源,例如下面這段C語言代碼:

Linux是如何創(chuàng)建進程的?為什么說Linux與其他操作系統(tǒng)不同?

拷貝或共享已經打開的資源

(7)將為新進程創(chuàng)建的 task_struct 結構體的指針返回給調用者,也即 do_fork() 函數。此時新創(chuàng)建的進程還沒有被投入運行。

現在回到 do_fork() 函數。如果調用 clone() 函數時,沒有傳遞 CLONE_STOPPED 參數,新創(chuàng)建的進程將被喚醒,并投入運行,這一過程的C語言代碼如下:

Linux是如何創(chuàng)建進程的?為什么說Linux與其他操作系統(tǒng)不同?

喚醒,并投入運行

到這里,一個新的進程就被 Linux 創(chuàng)建完畢了。

Linux 內核有意讓新創(chuàng)建的子進程先運行,因為子進程常常會立即調用 exec() 函數加載新的程序到內存中運行,這樣就避免了寫時拷貝的額外開銷。如果父進程首先執(zhí)行,顯然極有可能開始往地址空間寫入操作,導致拷貝動作發(fā)生。

小結

本節(jié)詳細的從C語言代碼層面分析了Linux內核創(chuàng)建進程的過程,可見,即使是復雜的操作系統(tǒng)代碼,也是通過一系列基本C語言語法和函數實現的。那么,Linux 是如何創(chuàng)建線程的呢?之前我們曾經提到,Linux 系統(tǒng)并不特別區(qū)分進程和線程,線程其實是一種特殊的進程,Linux 是如何實現這一“特殊”過程的呢?限于篇幅,下一節(jié)再說了,敬請關注。

責任編輯:華軒 來源: 今日頭條
相關推薦

2010-03-25 14:45:24

Linux桌面環(huán)境

2016-01-08 13:54:31

DebianLinux發(fā)行版

2009-12-14 18:27:21

Linux操作系統(tǒng)

2010-01-05 17:16:51

2010-01-06 15:41:07

Linux操作系統(tǒng)

2021-09-01 09:50:02

K8S容器

2024-02-26 08:49:32

NewbingAI模型

2009-12-14 17:36:18

2013-09-16 15:15:44

Linux操作系統(tǒng)

2019-04-28 10:30:30

Linux操作系統(tǒng)Namespace

2009-12-15 18:27:51

Linux操作系統(tǒng)

2022-09-29 09:17:47

進程Linux創(chuàng)建

2023-04-13 08:09:35

操作系統(tǒng)虛擬地址內存

2019-09-23 13:10:02

容器進程

2012-09-21 14:35:01

2009-08-28 10:43:38

2022-07-29 10:42:51

Linux隱私

2014-10-30 13:36:55

開源系統(tǒng)

2009-12-22 13:44:33

Linux操作系統(tǒng)

2020-12-17 18:30:44

華為鴻蒙智能手機操作系統(tǒng)
點贊
收藏

51CTO技術棧公眾號