Linux系統調用函數fork()用法詳解

火星人 @ 2014-03-09 , reply:0


Linux系統調用函數fork()用法詳解 這學期在學操作系統,老師布置了一個關於進程的實驗題,是在Linux系統中實現的,其中有涉及到fork()函數的調用,恰好我研究Ubuntu 也有一段時間了,就了解了下fork()函數,下面把自己實驗的一點心得貼上來,也希望能幫到各位初學者(我也是個初學者).
先看下我在網上搜索到的一篇文章,至於原作者找不到了,望諒解.如下: 1. 先看下面代碼:
#include
#include //pid_t類型定義
#include //函數fork(),getpid()定義
void 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 %d\n",getpid());
else
printf("i am the parent process, my process id is %d\n",getpid());
}
要搞清楚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,輸出 i am the child process...


我想你比較困惑的就是,為什麼看上去程序中互斥的兩個分支都被執行了.在一個程序的一次執行中,這當然是不可能的;但是你看到的兩行輸出是來自兩個進程,這兩個進程來自同一個程序的兩次執行.

下面是我的一點心得,關於子進程的調用點問題,如下:
2. 子進程的調用點詳解
子進程是從fork()函數開始執行的.範例:
#include
#include //pid_t類型定義
#include //函數fork(),getpid()定義
void main()
{
pid_t p1,p2;
p1=fork();
if(p1<0)
printf("error in fork!");
else if (p1 == 0)
printf("child process pid: %d\n",getpid());
else
printf("parent process pid: %d\n",getpid());
p2=fork();
if(p2<0)
printf("error in fork!");
else if (p2 == 0)
printf("child process pid: %d\n",getpid());
else
printf("parent process pid: %d\n",getpid());
}
上述程序的編譯執行結果如下:
jenner@Intrepid:~/Desktop$ gcc 01.c -o 01
jenner@Intrepid:~/Desktop$ ./01
child process pid: 14844
child process pid: 14845
parent process pid: 14844
parent process pid: 14843
child process pid: 14846
parent process pid: 14843
註釋:最初的43號進程執行兩個fork(),輸出兩個parent43,併產生子進程44號和45號;


44號進程從第一個fork()函數開始執行,輸出child44,調用第二個fork(),輸出parent44,併產生子進程46號;
45號進程從第二個fork()函數開始執行,輸出child45;
46號進程從第二個fork()函數開始執行,輸出child46;
至此程序結束.
注意:以上過程不是程序的先後運行過程,那六個輸出的先後順序是不確定的!
程序中所有進程的父子關係如下:
父進程43 ---子進程44
---子進程的子進程46
---子進程45
其中44號進程既是43號進程的子進程,又是46號進程的父進程.
以上是我的一些心得,看著可能有點繞口,耐心點,我也研究了好久呢,如果你看懂了,fork()函數也就算基本理解了!

順便也把老師布置的作業題也貼上來吧,呵呵,如下:
3. 題目:進程的創建:編製一段程序,使用系統調用fork( )創建兩個子進程,這樣在此程序運行時,在系統中就有一個父進程和兩個子進程在活動.讓每一個進程在屏幕上顯示一個字元:父進程顯示字元a,子進程分別顯示字元 b和字元c.試觀察、記錄並分析屏幕上,進程調度的情況.

代碼如下:
#include
#include
#include
void main()
{
pid_t p1,p2;
p1=fork();
if(p1<0)
printf("error in fork!\n");
else if (p1 == 0)
printf("child process b\n");
else
{


p2=fork();
if(p2<0)
printf("error in fork!\n");
else if (p2 == 0)
printf("child process c\n");
else
printf("parent process a\n");
}
}




[火星人 via ] Linux系統調用函數fork()用法詳解已經有3024次圍觀

http://www.coctec.com/docs/linux/show-post-50365.html