日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

fork的返回值

發布時間:2025/3/15 编程问答 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 fork的返回值 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

fork簡介:??????
?? fork英文原意是“分岔,分支”的意思,而在操作系統中,乃是著名的Unix(或類Unix,如Linux,Minix)中用于創建子進程的系統調用。?

【NOTE1】?
fork () 的作用是什么?換句話說,你用 fork () 的目的是什么??
――是為了產生一個新的進程,地球人都知道 :)
產生一個什么樣的進程??
――和你本來調用 fork () 的那個進程基本一樣的進程,其實就是你原來進程的副本;?
真的完全一樣嗎??
――當然不能完全一樣,你要兩個除了 pid 之外其它一模一樣的進程干什么,就算memory?
再多也不用這么擺譜吧??
哪里不一樣??
――當然最重要的是 fork () 之后執行的代碼不一樣,you know, i know :)?
怎么實現呢??
――如果是 Windows,它會讓你在 fork () 里面提供一大堆東西,指明這個那個什么的……?
我用的是 unix 啊?
――所以很簡單,unix 會讓兩個進程(不錯,原來是一個,unix 替你復制了一個,現在有兩個)?
在 fork () 之后產生不同:返回值不同。其中一個進程(使用新的 pid)里面的 fork () 返回零,?
這個進程就是“子進程”;而另一個進程(使用原來的 pid)中的 fork () 返回前面那個子進程的?
pid,他自己被稱為“父進程”?
然后呢??
――寫代碼的人又不笨,當然就根據返回值是否非零來判斷了,現在我是在子進程里面呢,還是在?
父進程里面?在子進程里面就執行子進程該執行的代碼,在父進程里面就執行父進程的代碼……?

??? 有鐵桿 windows fans 借此說明,windows 好啊,子進程用子進程的代碼,父進程用父進程的,?
你 unix 笨了吧,子進程包含父進程、子進程的代碼,父進程包含父進程子進程的代碼,豈不是多占用內存了嗎??
――據我所知,unix 代碼段都是可重入代碼,也就是說,進程復制,并不復制代碼段,若干個進程?
共享同一代碼段,增加的只是全局共享數據和對文件描述符的引用等,另外就是堆棧。你一個代碼?
長達 10M 的進程,fork () 出三四個子進程,只是增加一點內存占用(如果你沒有使用很多全局變量?
的話),而不是占用 40M 以上的內存。?

【NOTE2】?
程序?? 從?? fork?? 開始分支?? (稱分支不準確),?? 一路是主進程?? pid?? >?? 0?? (pid?? 是子進程ID)?? 一路是子進程?? pid?? ==?? 0?? 自此分成兩個任務?
其實fork的時候已經兩個分支了,數據段被復制了一份,因此pid有兩份???????
執行pid=fork()時,返回值賦給pid在兩個進程中運行,???????
fork會返回給父進程的那個>0的值,告訴調用者新建進程的pid????
子進程的fork返回值是0?????
更不用說if...else的比較也是在兩個進程中都做的了????

【NOTE3】?
fork的精辟剖析?
程序如下:?
#include <unistd.h>;?
#include <sys/types.h>;?
main ()

{ pid_t pid;?
pid=fork();?

?? if (pid < 0) printf("error in fork!");?
else if (pid == 0)?
?? printf("i am the child process, my process id is %dn",getpid());?
else?
printf("i am the parent process, my process id is %dn",getpid());?
}?

結果是?

[root@localhost c]# ./a.out?

i am the child process, my process id is 4286?

i am the parent process, my process id is 4285?

一:?
要搞清楚fork的執行過程,就必須先講清楚操作系統中的“進程(process)”概念。一個進程,主要包含三個元素:?

o. 一個可以執行的程序;?

o. 和該進程相關聯的全部數據(包括變量,內存空間,緩沖區等等);?

o. 程序的執行上下文(execution context)。?

不妨簡單理解為,一個進程表示的,就是一個可執行程序的一次執行過程中的一個狀態。操作系統對進程的管理,典型的情況,是通過進程表完成的。進程表中的每 一個表項,記錄的是當前操作系統中一個進程的情況。對于單 CPU的情況而言,每一特定時刻只有一個進程占用 CPU,但是系統中可能同時存在多個活動的(等待執行或繼續執行的)進程。一個稱為“程序計數器(program counter, pc)”的寄存器,指出當前占用 CPU的進程要執行的下一條指令的位置。當分給某個進程的 CPU時間已經用完,操作系統將該進程相關的寄存器的值,保存到該進程在進程表中對應的表項里面;把將要接替這個進程占用 CPU的那個進程的上下文,從進程表中讀出,并更新相應的寄存器(這個過程稱為“上下文交換(process context switch)”,實際的上下文交換需要涉及到更多的數據,那和fork無關,不再多說,主要要記住程序寄存器 pc指出程序當前已經執行到哪里,是進程上下文的重要內容,換出 CPU的進程要保存這個寄存器的值,換入CPU的進程,也要根據進程表中保存的本進程執行上下文信息,更新這個寄存器)。?

好了,有這些概念打底,可以說fork了。當你的程序執行到下面的語句:?

pid=fork();?

操作系統創建一個新的進程(子進程),并且在進程表中相應為它建立一個新的表項。新進程和原有進程的可執行程序是同一個程序;上下文和數據,絕大部分就是 原進程(父進程)的拷貝,但它們是兩個相互獨立的進程!此時程序寄存器pc,在父、子進程的上下文中都聲稱,這個進程目前執行到fork調用即將返回(此 時子進程不占有CPU,子進程的pc不是真正保存在寄存器中,而是作為進程上下文保存在進程表中的對應表項內)。問題是怎么返回,在父子進程中就分道揚 鑣。?

父進程繼續執行,操作系統對fork的實現,使這個調用在父進程中返回剛剛創建的子進程的pid(一個正整數),所以下面的if語句中pid<0, pid==0的兩個分支都不會執行。所以輸出i am the parent process...?

子進程在之后的某個時候得到調度,它的上下文被換入,占據 CPU,操作系統對fork的實現,使得子進程中fork調用返回0。所以在這個進程(注意這不是父進程了哦,雖然是同一個程序,但是這是同一個程序的另 外一次執行,在操作系統中這次執行是由另外一個進程表示的,從執行的角度說和父進程相互獨立)中pid=0。這個進程繼續執行的過程中,if語句中 pid<0不滿足,但是pid= =0是true。所以輸出i am the child process...?

為什么看上去程序中互斥的兩個分支都被執行了?在一個程序的一次執行中,這當然是不可能的;但是你看到的兩行輸出是來自兩個進程,這兩個進程來自同一個程序的兩次執行。?

fork之后,操作系統會復制一個與父進程完全相同的子進程,雖說是父子關系,但是在操作系統看來,他們更像兄弟關系,這2個進程共享代碼空間,但是數據 空間是互相獨立的,子進程數據空間中的內容是父進程的完整拷貝,指令指針也完全相同,但只有一點不同,如果fork成功,子進程中fork的返回值是0, 父進程中fork的返回值是子進程的進程號,如果fork不成功,父進程會返回錯誤。?

可以這樣想象,2個進程一直同時運行,而且步調一致,在fork之后,他們分別作不同的工作,也就是分岔了。這也是fork為什么叫fork的原因。?

在程序段里用了fork()之后程序出了分岔,派生出了兩個進程。具體哪個先運行就看該系統的調度算法了。?

如果需要父子進程協同,可以通過原語的辦法解決。?

二:?
進程的創建:?
創建一個進程的系統調用很簡單.我們只要調用fork函數就可以了.?
#include <unistd.h>?
pid_t fork();?

當一個進程調用了fork以后,系統會創建一個子進程.這個子進程和父進程不同的地方只有他的進程ID和父進程ID,其他的都是一樣.就象父進程克隆 (clone)自己一樣.當然創建兩個一模一樣的進程是沒有意義的.為了區分父進程和子進程,我們必須跟蹤fork的返回值. 當fork掉用失敗的時候(內存不足或者是用戶的最大進程數已到)fork返回-1,否則fork的返回值有重要的作用.對于父進程fork返回子進程的 ID,而對于fork子進程返回0.我們就是根據這個返回值來區分父子進程的. 父進程為什么要創建子進程呢?前面我們已經說過了Linux是一個多用戶操作系統,在同一時間會有許多的用戶在爭奪系統的資源.有時進程為了早一點完成任 務就創建子進程來爭奪資源. 一旦子進程被創建,父子進程一起從fork處繼續執行,相互競爭系統的資源.有時候我們希望子進程繼續執行,而父進程阻塞,直到子進程完成任務.這個時候 我們可以調用wait或者waitpid系統調用.?

?? 總結一下有三:?

1,派生子進程的進程,即父進程,其pid不變;?

2,對子進程來說,fork返回給它0,但它的pid絕對不會是0;之所以fork返回0給它,是因為它隨時可以調用getpid()來獲取自己的pid;?

3,fork之后父子進程除非采用了同步手段,否則不能確定誰先運行,也不能確定誰先結束。認為子進程結束后父進程才從fork返回的,這是不對的,fork不是這樣的,vfork才這樣。?


【NOTE4】?

首先必須有一點要清楚,函數的返回值是儲存在寄存器eax中的。?
其次,當fork返回時,新進程會返回0是因為在初始化任務結構時,將eax設置為0;?
在fork中,把子進程加入到可運行的隊列中,由進程調度程序在適當的時機調度運行。也就是從此時開始,當前進程分裂為兩個并發的進程。?
無論哪個進程被調度運行,都將繼續執行fork函數的剩余代碼,執行結束后返回各自的值。?

【NOTE5】?
對于fork來說,父子進程共享同一段代碼空間,所以給人的感覺好像是有兩次返回,其實對于調用fork的父進程來說,如果fork出來的子進程沒有得到 調度,那么父進程從fork系統調用返回,同時分析sys_fork知道,fork返回的是子進程的id。再看fork出來的子進程,由 copy_process函數可以看出,子進程的返回地址為ret_from_fork(和父進程在同一個代碼點上返回),返回值直接置為0。所以當子進 程得到調度的時候,也從fork返回,返回值為0。?
??? 關鍵注意兩點:1.fork返回后,父進程或子進程的執行位置。(首先會將當前進程eax的值做為返回值)2.兩次返回的pid存放的位置。(eax中)?

進程調用copy_process得到lastpid的值(放入eax中,fork正常返回后,父進程中返回的就是lastpid)?
子進程任務狀態段tss的eax被設置成0,?
fork.c 中?
p-&gt;tss.eax=0;(如果子進程要執行就需要進程切換,當發生切換時,子進程tss中的eax值就調入eax寄存器,子進程執行時首先會將eax的內容做為返回值)?
當子進程開始執行時,copy_process返回eax的值。?
fork()后,就是兩個任務同時進行,父進程用他的tss,子進程用自己的tss,在切換時,各用各的eax中的值.?

所以,“一次調用兩次返回”是2個不同的進程!?
看這一句:pid=fork()?
當執行這一句時,當前進程進入fork()運行,此時,fork()內會用一段嵌入式匯編進行系統調用:int 0x80(具體代碼可參見內核版本0.11的unistd.h文件的133行_syscall0函數)。這時進入內核根據此前寫入eax的系統調用功能號 便會運行sys_fork系統調用。接著,sys_fork中首先會調用C函數find_empty_process產生一個新的進程,然后會調用C函數 copy_process將父進程的內容復制給子進程,但是子進程tss中的eax值賦值為0(這也是為什么子進程中返回0的原因),當賦值完成后, copy_process會返回新進程(該子進程)的pid,這個值會被保存到eax中。這時子進程就產生了,此時子進程與父進程擁有相同的代碼空間,程 序指針寄存器eip指向相同的下一條指令地址,當fork正常返回調用其的父進程后,因為eax中的值是新創建的子進程號,所以,fork()返回子進程 號,執行else(pid&gt;0);當產生進程切換運行子進程時,首先會恢復子進程的運行環境即裝入子進程的tss任務狀態段,其中的eax 值(copy_process中置為0)也會被裝入eax寄存器,所以,當子進程運行時,fork返回的是0執行if(pid==0)。?

【NOTE5】?
理解它關鍵在于理解堆棧的切換和壓棧,彈棧!?
關于子進程的返回:?
子進程復制了父進程的棧內容,從高到低?
SS?
ESP?
EFLAGS?
CS?
EIP -----此是int 0x80 的下一條指令,也是子進程開始執行的地方!!!!?
DS?
ES?
FS?
EDX?
ECX?
EBX?
GS?
ESI?
EDI?
EBP?
EAX(0)?

由于 EAX = 0,所以子進程返回 0 給 fork.?

注:新進程的用戶棧設為其父進程的用戶棧(最后彈出的SS,ESP)。如果父子進程以copy_on_write方式共用用戶堆棧?
(Linux之下就是這樣的),而且在此之前父進程修改了該堆棧(如果父進程先返回,這幾乎是肯定的),那么,系統已經為父進程創建了該用戶棧的副本,父進程原來的用戶棧留給了子進程。那么新進程的系統棧已經清空,新進程回到了用戶態,返回到了函數fork。?

【NOTE6】?
關于fork的討論與評價:?
fork好不好?相比其他操作系統如Windows,Windows會有諸如CreateProcess這樣的函數來創建一個與生俱來兩手空空的獨立的新進程。然后還有一大堆參數,指手畫腳的告訴你這個那個是什么。。。?

煩!!!?

K.I.S.S. (Keep it simple,stupid.)是Unix的至高原則。?

fork 起源于 Unix 操作系統。那是貝爾實驗室的 K&R (這兩人是Unix和C語言之父) 的一項天才發明!!!?? Linux由于與生俱來就與Unix血濃于水,所以繼承了它的這個天才發明。?

這種方法效率是很高的。因為復制的代價是很低的。在計算機網絡的實現中,以及在 client/server 系統中的server 一方的實現中,fork 常常是最自然,最有效,最適宜的手段。很多人甚至懷疑,到底是先有 fork 還是先有 client/server,因為 fork 似乎就是專門為此而設計的 !更重要的好處是,這樣有利于父子進程間通過 pipe 建立起一種簡單有效的進程間通信管道,并且產生了操作系統的用戶界面即 shell 的管道機制。這一點,對于 Unix 的發展和應用推廣,對于 Uinx 程序設計環境的形成,對于 Unix 程序設計風格的形成,都有非常深遠的影響。可以說這是一項天才的發明,它在很大程度上改變了操作系統的發展方向。

總結

以上是生活随笔為你收集整理的fork的返回值的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。