溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

linux創(chuàng)建進(jìn)程的命令有哪些

發(fā)布時(shí)間:2023-03-13 10:09:01 來源:億速云 閱讀:138 作者:iii 欄目:建站服務(wù)器

這篇“l(fā)inux創(chuàng)建進(jìn)程的命令有哪些”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“l(fā)inux創(chuàng)建進(jìn)程的命令有哪些”文章吧。

linux創(chuàng)建進(jìn)程的命令:1、fork命令,可以從已存在進(jìn)程中創(chuàng)建一個(gè)新進(jìn)程,該新進(jìn)程為子進(jìn)程,而原進(jìn)程為父進(jìn)程;子進(jìn)程完全復(fù)制父進(jìn)程的資源。2、vfork命令,創(chuàng)建的子進(jìn)程與父進(jìn)程共享地址空間,也就是說子進(jìn)程完全運(yùn)行在父進(jìn)程的地址空間上。3、clone命令,可以將父進(jìn)程資源有選擇地復(fù)制給子進(jìn)程,而沒有復(fù)制的數(shù)據(jù)結(jié)構(gòu)則通過指針的復(fù)制讓子進(jìn)程共享。

Linux系統(tǒng)種創(chuàng)建進(jìn)程有fork、vfork、clone這個(gè)三名命令可供使用。

fork

fork創(chuàng)建一個(gè)進(jìn)程時(shí),子進(jìn)程只是完全復(fù)制父進(jìn)程的資源,復(fù)制出來的子進(jìn)程有自己的task_struct結(jié)構(gòu)和pid,但卻復(fù)制父進(jìn)程其它所有的資源。例如,要是父進(jìn)程打開了五個(gè)文件,那么子進(jìn)程也有五個(gè)打開的文件,而且這些文件的當(dāng)前讀寫指針也停在相同的地方。所以,這一步所做的是復(fù)制。這樣得到的子進(jìn)程獨(dú)立于父進(jìn)程, 具有良好的并發(fā)性,但是二者之間的通訊需要通過專門的通訊機(jī)制,如:pipe,共享內(nèi)存等機(jī)制, 另外通過fork創(chuàng)建子進(jìn)程,需要將上面描述的每種資源都復(fù)制一個(gè)副本。這樣看來,fork是一個(gè)開銷十分大的系統(tǒng)調(diào)用,這些開銷并不是所有的情況下都是必須的,比如某進(jìn)程fork出一個(gè)子進(jìn)程后,其子進(jìn)程僅僅是為了調(diào)用exec執(zhí)行另一個(gè)可執(zhí)行文件,那么在fork過程中對(duì)于虛存空間的復(fù)制將是一個(gè)多余的過程。但由于現(xiàn)在Linux中是采取了copy-on-write(COW寫時(shí)復(fù)制)技術(shù),為了降低開銷,fork最初并不會(huì)真的產(chǎn)生兩個(gè)不同的拷貝,因?yàn)樵谀莻€(gè)時(shí)候,大量的數(shù)據(jù)其實(shí)完全是一樣的。寫時(shí)復(fù)制是在推遲真正的數(shù)據(jù)拷貝。若后來確實(shí)發(fā)生了寫入,那意味著parent和child的數(shù)據(jù)不一致了,于是產(chǎn)生復(fù)制動(dòng)作,每個(gè)進(jìn)程拿到屬于自己的那一份,這樣就可以降低系統(tǒng)調(diào)用的開銷。所以有了寫時(shí)復(fù)制后呢,vfork其實(shí)現(xiàn)意義就不大了。

  fork()調(diào)用執(zhí)行一次返回兩個(gè)值,對(duì)于父進(jìn)程,fork函數(shù)返回子程序的進(jìn)程號(hào),而對(duì)于子程序,fork函數(shù)則返回零,這就是一個(gè)函數(shù)返回兩次的本質(zhì)。

  在fork之后,子進(jìn)程和父進(jìn)程都會(huì)繼續(xù)執(zhí)行fork調(diào)用之后的指令。子進(jìn)程是父進(jìn)程的副本。它將獲得父進(jìn)程的數(shù)據(jù)空間,堆和棧的副本,這些都是副本,父子進(jìn)程并不共享這部分的內(nèi)存。也就是說,子進(jìn)程對(duì)父進(jìn)程中的同名變量進(jìn)行修改并不會(huì)影響其在父進(jìn)程中的值。但是父子進(jìn)程又共享一些東西,簡(jiǎn)單說來就是程序的正文段。正文段存放著由cpu執(zhí)行的機(jī)器指令,通常是read-only的。

vfork

  vfork系統(tǒng)調(diào)用不同于fork,用vfork創(chuàng)建的子進(jìn)程與父進(jìn)程共享地址空間,也就是說子進(jìn)程完全運(yùn)行在父進(jìn)程的地址空間上,如果這時(shí)子進(jìn)程修改了某個(gè)變量,這將影響到父進(jìn)程。

  因此,上面的例子如果改用vfork()的話,那么兩次打印a,b的值是相同的,所在地址也是相同的。

  但此處有一點(diǎn)要注意的是用vfork()創(chuàng)建的子進(jìn)程必須顯示調(diào)用exit()來結(jié)束,否則子進(jìn)程將不能結(jié)束,而fork()則不存在這個(gè)情況。

  Vfork也是在父進(jìn)程中返回子進(jìn)程的進(jìn)程號(hào),在子進(jìn)程中返回0。

  用 vfork創(chuàng)建子進(jìn)程后,父進(jìn)程會(huì)被阻塞直到子進(jìn)程調(diào)用exec(exec,將一個(gè)新的可執(zhí)行文件載入到地址空間并執(zhí)行之。)或exit。vfork的好處是在子進(jìn)程被創(chuàng)建后往往僅僅是為了調(diào)用exec執(zhí)行另一個(gè)程序,因?yàn)樗筒粫?huì)對(duì)父進(jìn)程的地址空間有任何引用,所以對(duì)地址空間的復(fù)制是多余的 ,因此通過vfork共享內(nèi)存可以減少不必要的開銷。

clone

  系統(tǒng)調(diào)用fork()和vfork()是無參數(shù)的,而clone()則帶有參數(shù)。fork()是全部復(fù)制,vfork()是共享內(nèi)存,而clone() 是則可以將父進(jìn)程資源有選擇地復(fù)制給子進(jìn)程,而沒有復(fù)制的數(shù)據(jù)結(jié)構(gòu)則通過指針的復(fù)制讓子進(jìn)程共享,具體要復(fù)制哪些資源給子進(jìn)程,由參數(shù)列表中的 clone_flags來決定。另外,clone()返回的是子進(jìn)程的pid。

下面詳細(xì)了解fork命令(進(jìn)程創(chuàng)建)。

深入 fork 函數(shù)

在 Linux 中 fork 函數(shù)是一個(gè)非常重要的函數(shù),它從已存在進(jìn)程中創(chuàng)建一個(gè)新進(jìn)程。新進(jìn)程為子進(jìn)程,而原進(jìn)程為父進(jìn)程。

fork 函數(shù)的返回值:

  • 給父進(jìn)程返回子進(jìn)程的 pid

  • 給子進(jìn)程返回0

接下來我們舉例使用一下fork函數(shù) ()

linux創(chuàng)建進(jìn)程的命令有哪些

我們編譯,然后運(yùn)行一下:

linux創(chuàng)建進(jìn)程的命令有哪些

fork 的常規(guī)用法

  • 一個(gè)父進(jìn)程希望復(fù)制自己,使父子進(jìn)程同時(shí)執(zhí)行不同的代碼段。例如,父進(jìn)程等待客戶端請(qǐng)求,生成子進(jìn)程來處理請(qǐng)求。

  • 一個(gè)進(jìn)程要執(zhí)行一個(gè)不同的程序。例如子進(jìn)程從fork返回后,調(diào)用exec函數(shù)。

fork調(diào)用失敗的原因

  • 系統(tǒng)中有太多的進(jìn)程

  • 實(shí)際用戶的進(jìn)程數(shù)超過了限制

在重溫了一下 fork 函數(shù)的使用后,接下來我們來研究一個(gè)話題:

fork() 創(chuàng)建子進(jìn)程,操作系統(tǒng)做了哪些操作?

進(jìn)程調(diào)用 fork,當(dāng)控制轉(zhuǎn)移到內(nèi)核中的fork代碼后,內(nèi)核做了以下操作:

  • 分配新得內(nèi)存塊和內(nèi)核數(shù)據(jù)結(jié)構(gòu)給子進(jìn)程。

  • 將父進(jìn)程部分?jǐn)?shù)據(jù)結(jié)構(gòu)內(nèi)容拷貝至子進(jìn)程。

  • 添加子進(jìn)程到系統(tǒng)進(jìn)程列表中。

  • fork返回,開始調(diào)度器調(diào)度。

linux創(chuàng)建進(jìn)程的命令有哪些

父進(jìn)程執(zhí)行完 fork之前的代碼(before)后,調(diào)用 fork 創(chuàng)建子進(jìn)程,父子兩個(gè)執(zhí)行流分別執(zhí)行。注意:fork 之后,誰先執(zhí)行完全由調(diào)度器決定。

這里還有一個(gè)問題,當(dāng)fork之后,父子進(jìn)程代碼共享是 after 共享,還是所有代碼都進(jìn)行共享?為什么子進(jìn)程總準(zhǔn)確地執(zhí)行 fork 之后對(duì)應(yīng)的代碼?

答案: 所有代碼共享,因?yàn)镃PU記錄了進(jìn)程的執(zhí)行位置。

  • 代碼進(jìn)行匯編之后,會(huì)有很多行代碼,而且每行代碼加載到內(nèi)存之后,都有對(duì)應(yīng)的地址。

  • 因?yàn)檫M(jìn)程隨時(shí)都可能被中斷(可能并沒有執(zhí)行完),下次繼續(xù)執(zhí)行時(shí),還必須從之前的位置繼續(xù)運(yùn)行(并不是程序最開始或main函數(shù)處),這就要求 CPU 必須實(shí)時(shí)記錄下當(dāng)前進(jìn)程執(zhí)行的位置。

  • 所以,CPU內(nèi)有對(duì)應(yīng)的寄存器數(shù)據(jù),用來記錄當(dāng)前進(jìn)程的執(zhí)行位置,此寄存器叫做EIP,也稱作為pc(point code 程序計(jì)數(shù)器),用來記錄正在執(zhí)行代碼的下一行代碼的地址(上下文數(shù)據(jù))。

  • 當(dāng)子進(jìn)程創(chuàng)建時(shí),會(huì)修改其EIP。此時(shí)子進(jìn)程便會(huì)認(rèn)為EIP的中保存下的數(shù)據(jù),就是要執(zhí)行的代碼。


創(chuàng)建子進(jìn)程時(shí),操作系統(tǒng)給子進(jìn)程分配對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu),子進(jìn)程獨(dú)立運(yùn)行,因?yàn)檫M(jìn)程具有獨(dú)立性。

理論上,子進(jìn)程也要有自己的代碼和數(shù)據(jù),但是一般而言,創(chuàng)建子進(jìn)程沒有加載的過程,子進(jìn)程本身并沒有自己的代碼和數(shù)據(jù)。

所以,子進(jìn)程只能 "使用" 父進(jìn)程的代碼和數(shù)據(jù),而代碼是只讀的,父子共享不會(huì)沖突;而數(shù)據(jù)是可能被修改的,必須進(jìn)行分離。

這時(shí),操作系統(tǒng)便采用寫時(shí)拷貝的策略。

寫時(shí)拷貝

linux創(chuàng)建進(jìn)程的命令有哪些

OS 為何采用寫時(shí)拷貝技術(shù),對(duì)父子進(jìn)程進(jìn)行分離

  • 寫入時(shí)再進(jìn)行拷貝,是高效使用內(nèi)存的一種表現(xiàn)。

  • 提高了系統(tǒng)的運(yùn)行效率。

  • OS無法在代碼執(zhí)行前預(yù)知哪些空間會(huì)被訪問。

擴(kuò)展知識(shí):進(jìn)程終止和

進(jìn)程終止

當(dāng)進(jìn)程終止時(shí),操作系統(tǒng)釋放了進(jìn)程申請(qǐng)的相關(guān)內(nèi)核數(shù)據(jù)結(jié)構(gòu)和對(duì)應(yīng)的代碼的數(shù)據(jù),其本質(zhì)就是釋放系統(tǒng)資源,

1、進(jìn)程退出碼

進(jìn)程終止的常見方式:

  1. 代碼跑完,結(jié)果正確。

  2. 代碼跑完,結(jié)果不正確。

  3. 代碼沒有跑完,程序崩潰了。

區(qū)分第一種情況和第二種情況我們可以通過進(jìn)程的退出碼很清晰的辨別。

關(guān)于學(xué)習(xí)的 C語言中 main 函數(shù)的返回值,其中 main 函數(shù)的返回值就是進(jìn)程的退出碼。其意義是返回給上一級(jí)進(jìn)程,用來評(píng)判該進(jìn)程執(zhí)行結(jié)果。

現(xiàn)在我們編寫一個(gè)簡(jiǎn)單的 C 程序。

linux創(chuàng)建進(jìn)程的命令有哪些

然后我們可以通過 echo $? 獲取最近一個(gè)進(jìn)程的退出碼。

linux創(chuàng)建進(jìn)程的命令有哪些

進(jìn)程的返回值有 0 和非0兩種情況,其中 0 表示程序成功運(yùn)行并結(jié)果正確,而非0表示成功運(yùn)行但結(jié)果有誤,非零值有無數(shù)個(gè),不同的非零值就可以就表示著不同的錯(cuò)誤,方便我們定義錯(cuò)誤的原因。

那常見的錯(cuò)誤信息有哪些呢?

我們可以使用 strerror 將其打印出來

linux創(chuàng)建進(jìn)程的命令有哪些

結(jié)果如下:

linux創(chuàng)建進(jìn)程的命令有哪些

linux創(chuàng)建進(jìn)程的命令有哪些

發(fā)現(xiàn) linux 下,共有133條錯(cuò)誤碼

當(dāng)然,程序崩潰的時(shí)候,退出碼沒有意義。

眾所周知,Linux 是用C語言寫的,其中命令本質(zhì)就是C語言程序,所以我們可以簡(jiǎn)單的拿 ls 命令來舉例

linux創(chuàng)建進(jìn)程的命令有哪些

而 2 號(hào)退出碼對(duì)應(yīng)的報(bào)錯(cuò)信息:

linux創(chuàng)建進(jìn)程的命令有哪些

2、exit 與 _exit

關(guān)于終止一個(gè)進(jìn)程可以使用 return 語句,還可以調(diào)用 exit 和 _exit 函數(shù)

exit函數(shù):

linux創(chuàng)建進(jìn)程的命令有哪些

_exit函數(shù):

linux創(chuàng)建進(jìn)程的命令有哪些

關(guān)于這兩個(gè)函數(shù)的區(qū)別有很多,我們先舉一個(gè)小例:

我們接下來使用 printf 打印一條信息,然后sleep三秒,再使用 exit 退出,并觀察結(jié)果

linux創(chuàng)建進(jìn)程的命令有哪些

因?yàn)槲覀儙狭?\n ,加上 \n 會(huì)刷新緩沖區(qū),屏幕上即出現(xiàn)我們打印的內(nèi)容。

linux創(chuàng)建進(jìn)程的命令有哪些

如果我們不帶上 \n ,我們?cè)儆^察結(jié)果:

linux創(chuàng)建進(jìn)程的命令有哪些

發(fā)現(xiàn):因?yàn)闆]有 \n ,所以 printf 中的內(nèi)容并沒有在休眠前被打印出來,而是調(diào)用 exit 后將緩沖區(qū)的內(nèi)容刷新出來輸出在屏幕上。

接下來我們使用 _exit 函數(shù)

linux創(chuàng)建進(jìn)程的命令有哪些

運(yùn)行可執(zhí)行文件 b:

linux創(chuàng)建進(jìn)程的命令有哪些

發(fā)現(xiàn)什么內(nèi)容都沒有被打印出來,使用 echo $? 打印最近進(jìn)程退出碼,發(fā)現(xiàn) b 文件確實(shí)被執(zhí)行了。

這說明,exit是庫函數(shù),而_exit 是系統(tǒng)調(diào)用,其退出進(jìn)程時(shí)并沒有刷新緩沖區(qū)中的內(nèi)容。

linux創(chuàng)建進(jìn)程的命令有哪些

此時(shí)我們便能得出一個(gè)結(jié)論:

printf 數(shù)據(jù)是保存在"緩沖區(qū)"中的,exit可以將其刷新,而系統(tǒng)調(diào)用接口_exit不能將其刷新。所以,緩沖區(qū)必定不在操作系統(tǒng)內(nèi)部,而是由C標(biāo)準(zhǔn)庫維護(hù)的。

以上就是關(guān)于“l(fā)inux創(chuàng)建進(jìn)程的命令有哪些”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI