星期三, 3月 08, 2017

[ C ] Fork() 和 Zombie


Fork()是複製一份和自己一模一樣的process出來,
回傳的值是pid,
所以可以用判斷pid的方式,把程式分成parent和child部份,
注意的是,
他是從fork()之後的程式碼開始執行起,
如果在那之前會執行不到。

=====Output=====
#####Now pid [8654]
I am the parent process, Count is 0 , ID is 8654 , Parent ID is 32489 , fork id is 8655
Process End
I am the child process, Count is 0 , ID is 8655 , Parent ID is 8654 , fork id is 0
Process End

SourceCode

"The process that has terminated, but whose parent hasn’t yet waited for it."

1. 如果parent先死掉,那child還在執行時,不會變成zombie,因為會由init(pid 1)來接收,並且wait()他結束。

2. zombie是指child結束了,要等待parent來處理child結束後的事,但這時一直都沒人處理。

zombie process的形成是因為parent還沒結束,
在產生child後,child執行完後時,
而parent process卻還沒執行完畢,
在這時child process執行完了就會變成zombie。

====================================================
vodka     8990  0.0  0.0   4088   664 pts/7    S    20:10   0:00 ./a.out
vodka     8992  0.0  0.0      0          0 pts/7    Z    20:10   0:00 [a.out] <defunct>
vodka     8996  0.0  0.0   9380  2204 pts/7    S+   20:10   0:00 grep a.out
====================================================

他會佔著一些空間不放,像是process id / termination status ...
佔據太多pid,process達到了上限,就無法再執行程式。

處理方法有以下幾種:
1. 在parent裡就宣告說我不需要知道child process的結束狀態。
signal(SIGCHLD, SIG_IGN);

2. 兩次的fork讓init 來接收child。
因為linux會在一個process結束時,自動把該process的parent變成init,
然後該process就由init所接管。
所以利用這樣的概念,
Step 1:
Process A => fork() -> parent繼續做他的事,child (B) 再去fork另一個process。
Step 2:
Process B => fork -> parent跳離(不執行其他動作),child去做自己的事。
Step 3:
如此一來在Process B時,因為parent結束了,所以child歸init管。



3. 利用wait來等待
    3-1 用wait來等全部child
           int i = wait(NULL);
           printf("waiting for pid [%d]\n",i);

    3-2 用waitpid來等特定pid
           waitpid(pid, NULL, WNOHANG);

WaitSourceCode
TwiceForkSourceCode

Ref
Ref_2
Ref_3
Ref_4

沒有留言: