歡迎光臨
每天分享高質量文章

宋寶華: Linux僵屍行程可以被“殺死”嗎?

什麼是僵屍

首先要明確一點,僵屍行程的含義是:子行程已經死了,但是父行程還沒有wait它的一個中間狀態,這個時候子行程是一個僵屍。正常情況下子死,父wait,清理掉子行程的task_struct,釋放子行程的PID:

編譯上述程式,執行,我們看到2個a.out行程:

殺死子行程4578,看到父行程的列印:

之後,4578會消失,因為父行程執行到了wait,也知道了子行程是被訊號2殺掉的。

但是如果子行程死了,父行程不執行到wait,比如把上圖中的”#if 0″改為”#if 1″,殺死子行程後,子行程就是一個僵屍:

我們重新執行,當我們用kill -2殺掉子行程4628後,我們發現4628成為一個僵屍,狀態變為Z+,名字上也加了一個棺材[],成為[a.out]:

僵屍不可能被殺死

我們看到上面4628是個僵屍很不爽,所以我們想把它幹掉,據說Linux有個訊號9,神擋殺神,佛擋殺佛,我們現在來用kill -9幹掉4628:

從上圖可以看出,我們把4628用kill -9捅了好多刀,但是最後看4628這個僵屍,還是沒有消失。

因為僵屍已經是死了,它不可能再次被殺死,你給它捅一萬刀,它也是個死人,不可能再次死!

僵屍不可能被殺死,因為它已經死了!只等父行程來wait清理屍體了。

一個僵屍可以被殺死的假象

下麵的這個程式證明“僵屍可以被殺死”

我們在主執行緒裡面,pthread_create()建立執行緒後,pthread_exit()退出,這個時候我們會發現,在ps命令裡面,a.out顯示為一個僵屍:

這個時候我們來殺死4730這個僵屍:

kill -9 4730

我們會驚奇地發現,4730真地會從ps命令裡面消失!

我們把時間軸拉回呼用”kill -9 4730″之前。剛才我們“看起來”能殺死僵屍的本質原因是,當主執行緒4730呼叫pthread_exit()退出後,主執行緒4730的狀態確實是僵屍了,但是該行程裡面的4731執行緒,卻沒有死:

看看4731:

4731是活著的,證明整個行程並沒有掛。

那麼,根據POSIX標準關於訊號(signal)的定義,當我們執行kill
-9
4730(4730是4730和4731的TGID,也是整個行程使用者態視角的PID)的時候,是要殺死整個4730行程的,所以這個時候4731被我們殺死,整個行程就都死了,這個時候,執行到父行程的wait邏輯,導致僵屍消失。

所以,在本例中,kill -9 4730看起來是”殺死了僵屍”,實際是殺死了4731,導致整個行程死。

(完)

贊(0)

分享創造快樂