2011-12-03 134 views
0

我一直在學習過去幾天的fork()函數,並且一直在做一些實驗來知道它是如何工作的。在這樣做的時候,我找到了一些我不瞭解的有趣代碼。下面是代碼:fork()的輸出混亂

int main(int argc, char *argv[]) 

{ 
int p,m; 
    p = getppid(); 
    printf("%d\n",p); 

if(fork() == 0) { 
    p = getppid(); 
    printf("%d\n",p); 
} 

if(fork() == 0) { 
    p = getppid(); 
    printf("%d\n",p); 
} 

if(fork() == 0) { 
    p = getppid(); 
    printf("%d\n",p); 
} 

if(fork() == 0) { 
    p = getppid(); 
    printf("%d\n",p); 
} 



return 0; 
} 

的輸出是這樣的:

$./a.out 
6117 
6460 
1 
[email protected]:~/forkbomb$ 1 
1 
1 
1 
1 
1 
1 
1 
1 
1 
1 
1 
6473 

這將是非常好的你,如果你爲什麼初始化爲1出現在輸出的PID給我解釋一下。 如果有幫助,我想澄清一下,我試圖從給定的一個創建5個進程。那麼你能告訴我正確的方法嗎? 謝謝

+0

對於初學者,您*不*創建5個過程。我認爲你正在創建16個進程。由於您不在父母身邊等待孩子,所以孩子被初次接受,因此ppid 1。 –

回答

2

如果子進程的父母在孩子面前退出或死亡,則該孩子被稱爲孤兒進程,並被init採用。這意味着孩子的PPID(父PID)變爲1.這解釋了你的輸出,因爲它來自getppid()

爲了解釋這是顯示的行數,讓號碼的代碼行:

1 int p,m; 
2  p = getppid(); 
3  printf("%d\n",p); 
4 
5 if(fork() == 0) { 
6  p = getppid(); 
7  printf("%d\n",p); 
8 } 
9 
10 if(fork() == 0) { 
11  p = getppid(); 
12  printf("%d\n",p); 
13 } 
14 
15 if(fork() == 0) { 
16  p = getppid(); 
17  printf("%d\n",p); 
18 } 
19 
20 if(fork() == 0) { 
21  p = getppid(); 
22  printf("%d\n",p); 
23 } 

現在讓我們來算所有執行的每個printf()的過程。第3行的printf()顯然只能由原始父進程執行。第7行的printf()僅由原始父進程的第一個孩子執行,因爲fork()在孩子中返回0。現在,第9行由兩個過程實現:原始父母和其第一個孩子。他們兩個都分叉並且他們的兩個孩子(即原始父母的第二個孩子和原始父母的第一個孩子的第一個孩子)在第12行執行printf()。第14行由4個過程實現(原始父母,孩子和原始父母的第一個孩子的第一個孩子)。他們都在第15行產生了一個孩子,所有四個孩子都在第17行執行printf()。多達8個過程到達第19行。每個分支和最後一代產生的8個孩子在第22行執行最後的printf()

第一個printf()被執行1次。 第二個printf()執行1次。 第三個printf()執行2次。 第四個printf()執行4次。 第五個printf()執行8次。

這是總共16個並且與您的輸出一致。顯示的一些PPID等於1,表示給定的父母執行得如此之快,以至於該孩子在達到給定的printf()之前被init採用。其他值大於1表示給定進程的父進程在孩子到達printf()時仍在運行。很可能,多次執行該程序會導致產量有所不同。

因此,您不會創建4個子進程,而是創建4個子進程。這是因爲您的子級從產生它們的fork()返回時繼續執行。這意味着一些fork()不僅會由原始父母執行,還會由其子代執行,從而創建一系列新流程。如果您只想創建4個孩子,則應確保剩餘分叉只發生在父母中。

3

家長從打印其父母的PID開始。然後繼續分岔四個孩子(C1..4),然後退出。

C1打印它的父PID,然後繼續分叉它自己的三個孩子。 C2打印它的父PID,然後繼續分叉它自己的兩個孩子。 C3打印其父PID ...

每個分叉的孩子在創建它的if塊之後繼續運行,因此會創建相當多的孩子。

當父進程退出時,子進程被重新設置爲init,進程號爲1。確切的輸出結果會因運行而異,具體取決於兒童安排的時間和方式以及父母的離開時間。

如果您只想創建五個進程,請確保孩子完成後退出!

if(fork() == 0) { 
    p = getppid(); 
    printf("%d\n",p); 
    exit(0); 
} 

如果你想父母,等待它的孩子們都已經完成了它退出自己之前,你應該看看wait家庭的功能。

0

你錯過了什麼,當你分叉時,有兩個進程的代碼的相同副本從分叉處繼續。

父節點獲取返回的子節點的pid,子節點返回0。 所以你分叉了16個進程(4階乘),因爲在每個分叉處你都會使進程數加倍。

如果您在最後添加sleep()以確保父進程掛起足夠長的時間,那麼您將得到父子節點中的實際父pid(只需在返回前添加sleep(2))。

我的輸出是:

所有的
> ./x 
19291 
21686 
21686 
21687 
21688 
21687 
21687 
21688 
21689 
21691 
21690 
21689 
21695 
21686 
21686 
21694 
0

首先,射出已經來自於父進程(ES)的1的。然後,父級成爲系統初始化進程1

如果您還對1的數量感到不滿,您會得到: 最初的過程會分叉4個孩子,這是叉子的第一個孩子3,有兩個孩子,每個叉子2個,三個孩子叉子1和四個不會進一步分叉。這使得總共1 + 1 + 4 + 3 + 2 + 1 + 4 = 16個過程。

0

該程序將在四個fork()部分中創建1 + 2 + 4 + 8 = 15個進程(如果我們加上原始進程,則爲16個進程)。也許你想要做的是這樣的:

if(fork() == 0) { 
    p = getppid(); 
    printf("%d\n",p); 
} else 
    return 0; 

getppid()將返回1,如果它的父母已經走了。由於我們不知道系統如何安排這些過程,因此您可以看到這可能發生在您的程序中。