行程與行程抽象

wait 與回收子行程(reaping)

/ reaping, 'REE-ping' /

想像一位父母派孩子去跑腿。孩子回來時,父母聽取回報、簽核,到那時這趟差事才算真正了結。在行程的世界裡,這就是 wait 與回收:父行程用 wait 系統呼叫暫停,直到某個子行程結束,然後收取子行程的退出狀態,而這個收取的動作讓作業系統終於能移除那個結束了的子行程。

當父行程呼叫 wait(或對特定子行程呼叫 waitpid)時,作業系統做兩件事。若子行程仍在執行,父行程阻塞直到它終止。一旦子行程已終止,wait 把子行程的退出狀態回傳給父行程,接著作業系統刪除子行程殘留的記帳資料——它的 PCB 與行程表紀錄。第二步就是回收:收取狀態並清出那個位置。沒有它,終止的子行程便無法被完全移除,因為作業系統必須保留它的退出狀態直到有人讀取。建立多個子行程的父行程應當為每一個都呼叫 wait。

回收之所以重要有兩個原因:它是父行程得知子行程結果(成功、失敗、被信號殺死)的方式,也是系統避免累積殭屍的方式。初學者常見的臭蟲是忘了 wait,這會留下越積越多的殭屍子行程,浪費行程表的紀錄。有一個有用的微妙之處:父行程可以在子行程死去時被通知(透過 SIGCHLD 信號)並當下回收它,而不必阻塞;而若父行程在未回收的情況下退出,那些成了孤兒(如今也已終止)的子行程被 init 繼承,由它回收,所以它們不會永遠是殭屍。

在 fork 出一個子行程後,父行程呼叫 wait(&status)。它阻塞直到子行程退出,之後 status 持有子行程的退出碼,子行程的行程表位置被釋放;子行程此時完全消失。

wait 阻塞直到子行程退出,回傳它的狀態,並回收它。

回收是必須的,不是可選的。從不 wait 的父行程會留下殭屍子行程,佔用行程表紀錄,直到父行程退出、由 init 回收它們。

又称
wait()waitpidreapingcollecting a child回收等待子行程