1. 程式人生 > >【Linux】關於理解fork()函式的簡單例子

【Linux】關於理解fork()函式的簡單例子

1.fork()函式

fork()是一個系統呼叫,用於建立程序。建立的這個程序與原來程序幾乎完全相同。這個新產生的程序稱為子程序。一個程序呼叫fork()函式後,系統先給新的程序分配資源,例如儲存資料和程式碼的空間。然後把原來的程序的所有值都複製到新的新程序中,只有少數值與原來的程序的值不同。相當於克隆了一個自己。需要注意的一點:就是呼叫fork之後,兩個程序同時執行的程式碼段是fork函式之後的程式碼,而之前的程式碼已經由父程序執行完畢。下面來看一個很簡單的例子。
fork()返回兩個值

  • 返回一個大於0的值給父程序
  • 返回0給子程序
  • 返回其他值說明fork失敗了

2.關於fork的一個簡單例子

#include<stdio.h>
#include<unistd.h>
int main()
{
	pid_t pid;
	int count = 0;
	pid = fork();	//fork一個程序
	if(pid == 0) {               //pid為0,
		printf("this is child process, pid is %d\n",getpid());//getpid返回的是當前程序的PID
		count+=2;
		printf("count = %d\n",count);
	} else if(pid > 0) {
		printf("this is father process, pid is %d\n",getpid());
		count++;
		printf("count = %d\n",count);
	} else {
		fprintf(stderr,"ERROR:fork() failed!\n");
	}
	return 0;
}

下面是執行結果:
這裡寫圖片描述
  有人可能會對這個執行結果產生一種錯覺,就是程式中if語句的兩條分支if(pid == 0)和else if(pid > 0)都得到了執行。其實完全不是這麼回事,出現這種執行結果的原因是因為,在main()函式呼叫fork了,建立了一個新的程序,這個程序稱為原來程序的子程序。子程序與原來的程序併發執行,誰先誰後沒有規律,由作業系統排程決定。
  我們用gdb工具對這個程式單步執行除錯一下,可能會對這個過程瞭解的更清晰一些。

3.使用gdb除錯父程序。

1.輸入gdb a.out然後輸入start開始除錯,此時終端顯示即將執行的程式碼
這裡寫圖片描述
2.輸入n,執行當前一行程式碼,同時顯示下一條將執行的程式碼


這裡寫圖片描述
即將建立一個子程序,當前程序為父程序。
3.再輸入n執行pid=fork()語句
這裡寫圖片描述
這個時候,終端上顯示

Detaching after fork from child process 2755.
this is child process, pid is 2755
count = 2

這個時候,說明已經新建了一個子程序,子程序PID是2755,而且由於我們現在單步除錯的是父程序,並不影響子程序的執行。這個子程序只有幾行程式碼,這個時候已經執行完了,並且在終端上顯示了執行結果,就是下面兩行內容。

this is child process, pid is 2755
count = 2

4. 輸入p pid看一下fork函式返回給父程序的值是不是子程序的PID
這裡寫圖片描述
果然就是子程序的PID值。
5.輸入n接著執行判斷語句
這裡寫圖片描述
由於pid的值為2755,因此跳過了if(pid==0)分支內的語句,轉而判斷pid是否大於0
6.輸入n接著判斷pid是否大於0
這裡寫圖片描述
pid的值大於0,執行分支內的語句。
7.接著輸入n,直到程式正常結束
這裡寫圖片描述

上面是父程序的除錯過程,其實子程序也可以用gdb來除錯,下次再說。

4.使用ps aux命令檢視父程序和子程序

ps aux命令可以檢視系統中正在執行的所有程序,不過我們這個例子程式碼很少,系統瞬間就能執行完畢,用ps aux命令根本捕捉不到。因此我們在程式碼中做一些修改。

#include<stdio.h>
#include<unistd.h>
int main()
{
	pid_t pid;
	int count = 0;
	pid = fork();	//fork一個程序
	if(pid == 0) {               //pid為0,
		printf("this is child process, pid is %d\n",getpid());
		count+=2;
		printf("count = %d\n",count);
	} 	else if(pid > 0) {
		printf("this is father process, pid is %d\n",getpid());
		count++;
		printf("count = %d\n",count);
	} else {
		fprintf(stderr,"ERROR:fork() failed!\n");
	}
	sleep(10);//新加入的行,讓程式在這裡暫停10秒,父程序和子程序都會執行這行程式碼
	return 0;
}

我們在第30行加入了一條語句,讓程式暫停10s。重新編譯程式,然後執行程式,輸入./a.out後,快速切換到另外一個終端(如果你手速慢的話,多暫停一會兒就可以),輸入ps aux檢視正在執行的程序。
執行程式:
這裡寫圖片描述

切換終端,輸入ps aux檢視程序
這裡寫圖片描述
可以看到a.out程式產生了兩個程序,父程序PID是2928,子程序PID是2929。