1.僵屍進程、孤兒進程
僵屍進程:當一個子進程結束運行(一般是調用exit、運行時發生致命錯誤或收到終止信號所導致)時,子進程的退出狀態(返回值)會報給操作系統,系統則以SIGCHLD信號告知父進程,此時子進程的進程控制塊(PCB)仍駐留在內存中。父進程收到SIGCHLD后,會調用wait()函數獲取子進程的退出狀態,然后內核就可以從內存中釋放已結束的子進程的PCB;而如若父進程沒有這么做的話,子進程的PCB就會一直駐留在內存中,即成為僵屍進程。
孤兒進程:當父進程退出,而它的一個或多個子進程還在運行,那么那些子進程將成為孤兒進程。孤兒進程將被init進程(進程號為1)所收養,並由init進程對它們完成狀態收集工作,因此孤兒進程並沒有什么危害,系統中會經常有這種情況。
2.wait、waitpid函數的使用方法
wait、waitpid函數由父進程調用來讀取子進程的返回信息,使子進程完全終止。
【1】pid_t wait(int *status);
wait函數會在父進程中阻塞,等待子進程結束,如果子進程結束,則返回子進程的PID。如果沒有子進程則立刻返回-1。
【2】pid_t waitpid(pid_t pid, int *status, int options);
waitpid函數等待子進程結束(options設置為WNOHANG時為非阻塞),如果子進程結束,則返回子進程的PID。如果沒有子進程則立刻返回-1,如果是非阻塞的並且子進程還沒有結束,則返回0。
由於這兩個函數會阻塞等待(非阻塞時也需要輪詢執行),所以常規使用方式為:當子進程退出時會給父進程發送SIGCHID信號,因此父進程捕獲SIGCHID信號,並在信號處理函數中調用waitpid函數來結束一個子進程。如下:
void sig_chld(int signo) { pid_t pid; int stat; while((pid = waitpid(-1, &stat, WNOHANG)) > 0){ printf("child %d terminated\n", pid); } return; } signal(SIGCHLD, sig_chld);
3.問題
問題1:如果有多個子進程,則任意一個子進程結束時,wait函數就會返回,所以此時可以循環判斷wait返回-1時(另外返回-1時,errno 等於EINTR時表示中斷,所以此時需要繼續循環等待),才表示所有子進程都退出了。