為什麼我的進程在我註銷後仍在運行?

為什麼我的進程在我註銷後仍在運行?

透過登入後ssh,我在中輸入以下命令bash

sleep 50000000000000 &

然後我是kill -9sleep進程的父進程(即bash)。然後終端機窗口同時斷開連線。

當我再次登入時,發現sleep進程還活著。

問題: 為什麼sleep我退出並關閉終端機後進程還能存活?在我看來,除了守護進程和nohup程序之外的所有內容都將在註銷期間被殺死。如果sleep這樣能活下來,是不是就代表我可以用這個方法來代替命令了nohup呢?

答案1

太爾;博士:

sleep為什麼我退出並關閉終端後進程還能存活?在我看來,除了守護進程和nohup程序之外的所有內容都將在註銷期間被殺死。如果sleep這樣能活下來,是不是就代表我可以用這個方法來代替命令了nohup呢?

除非bash所產生的實例設定ssh了該huponexit選項,否則在退出/登出時不會以任何方式終止任何進程,並且huponexit設定該選項後,kill -9在 shell 上使用並不是nohup在 shell 子進程上使用的良好替代方案;nohup在 shell 的子進程上仍然可以保護它們免受非來自 shell 的 SIGHUP 的影響,即使這並不重要,nohup仍然是首選,因為它允許 shell 優雅地終止。


其中bash有一個名為 的選項huponexit,如果設定該選項,將bash在退出/登出時使其子項 SIGHUP ;

在互動中未登入 bash實例,例如在bash由 產生的實例中gnome-terminal,該選項將被忽略;無論huponexit是設置或未設置,bash的子級在bash退出時都不會被 SIGHUPped;

在互動中登入 bash實例,例如在bash由 產生的實例中ssh,不會忽略此選項(但預設未設定);如果huponexit設定了,bash則 的子層級將在bash退出/登出時發出 SIGHUPped;如果huponexit未設置,則 的子級在退出/登出時bash不會發出 SIGHUPped ;bash

因此,一般來說,從互動式登入bash實例退出/登出,除非huponexit設定了該選項,否則不會使 shell 對其子級進行 SIGHUP,並且從互動式非登入bash實例退出/登出也不會使shell對其子級進行SIGHUP不管;

然而,在這種情況下,這是無關緊要的:kill -9 sleep無論如何,using 都會生存,因為殺死它的父進程 ( bash) 不會給後者留下執行的機會任何事物到前者(即,例如,如果當前bash實例是登入bash實例並且huponexit設定了該選項,則對其進行 SIGHUP)。

除此之外,與其他訊號(例如發送到 的 SIGHUP 訊號bash)不同,SIGKILL 訊號永遠不會傳播到進程的子進程,因此sleep甚至不會被終止;

nohup啟動一個不受 SIGHUP 訊號影響的進程,這是不同的;它將防止進程在接收到 SIGHUP 訊號時掛起,在這種情況bash下,如果huponexit設定了選項並且 shell 退出,則互動式登入實例可以接收該訊號;因此從技術上講,使用未設定nohup選項在互動式登入bash實例中啟動進程huponexit將防止進程在收到 SIGHUP 訊號時掛起,但登出/登出 shell 無論如何都不會 SIGHUP ;

然而,一般來說,當nohup需要阻止來自父 shell 的 SIGHUP 訊號時,沒有理由更喜歡kill -9on 父方法而不是nohupon 子方法;相反,應該是相反的。

使用該方法殺死父進程kill -9不會給父進程留下優雅退出的機會,而使用該nohup方法啟動子進程允許父進程被其他信號終止,例如 SIGHUP (舉一個在上下文中有意義的例子的孩子開始使用nohup),這允許它優雅地退出。

答案2

bash預設情況下退出時不向子進程發送 HUP 訊號。更詳細(感謝@kos),它從來沒有這樣做過非登入 shell

您可以配置 bash 來執行此操作登入外殼如果設定該選項huponexit。在終端機中,執行以下操作:

[romano:~] % bash -l

(這將啟動一個新的「登入」外殼)

romano@pern:~$ shopt -s huponexit
romano@pern:~$ sleep 1234 &
[1] 32202
romano@pern:~$ exit
logout

現在檢查進程sleep

[romano:~] % ps augx | grep sleep
romano   32231  0.0  0.0  16000  2408 pts/11   S+   15:23   0:00 grep sleep

……未運作:它已收到 HUP 訊號並按請求退出。

答案3

如果sleep能這樣生存下去,是否就代表我可以用這個方法來代替nohup命令了?

kill -9這確實不是一個人該走的路。這就像用槍射擊電視以將其關閉一樣。除了喜劇成分之外,沒有任何優勢。進程無法捕獲或忽略SIGKILL。如果您不給進程機會完成正在執行的操作並進行清理,它可能會留下損壞的檔案(或其他狀態)並且無法重新啟動。kill -9當其他方法都不起作用時,這是最後的希望。


為什麼當我註銷並關閉終端時睡眠進程可以存活。在我看來,註銷時除了守護程序和 nohup 程序之外的所有程序都會被殺死。

你的情況會發生什麼事:

的父進程sleep是目前正在運行的bashshell。當您kill -9執行 bash 時,bash 進程沒有機會將 a 傳送SIGHUP到其任何子進程,因為SIGKILL(由 發送kill -9)無法被該進程捕獲。睡眠進程繼續運作。睡眠現在變成了孤兒行程

init (PID 1) 進程執行一種稱為 reparenting 的機制。這意味著 init 進程現在成為該孤立進程的父進程。 init 是一個例外,進程可以成為它的子進程,因為它收集丟失其原始父進程的進程。順便說一句:守護程式(如sshd)在「進入背景」時會執行此操作。

如果這種情況沒有發生,孤立進程稍後(完成後)將成為殭屍進程。這就是waitpid()未呼叫時發生的情況(父進程的責任在該進程被殺死時無法履行)。 initwaitpid()在特定的時間間隔內呼叫以避免殭屍子程序。

答案4

使用&將使程式作為背景運行。要在後台查看該程序,請使用bg命令,並使其再次作為前台運行,請運行fg

是的,有很多方法可以讓程式在主終端退出時保持運作。

相關內容