到了新公司以後,第一次參加會議時聽到大家在討論一個問題:
為何有些時候離開shell的時候,background(BG) jobs不會被終結?
由於同事們都有更重要的事要處理,而我才剛進來幾天,還沒啥工作,就查了一下原因。發現其實理由也蠻單純的(參考TLPI一書的section 34.6)。首先,只有兩種情況會讓kernel發出SIGHUP給controlling terminal:
為何有些時候離開shell的時候,background(BG) jobs不會被終結?
由於同事們都有更重要的事要處理,而我才剛進來幾天,還沒啥工作,就查了一下原因。發現其實理由也蠻單純的(參考TLPI一書的section 34.6)。首先,只有兩種情況會讓kernel發出SIGHUP給controlling terminal:
1. Terminal driver偵測到 “disconnect”
2. GUI的terminal window關閉
再依據目前的controlling process是否為shell,會有兩種可能狀況:
1. Shell會註冊此訊號的處理方式,並將SIGHUP傳給shell所生出的所有process groups (jobs)
2. 若非shell(一般沒有攔截SIGHUP,則kernel會將SIGHUP送給foreground(FG) job),然後將解除session所相關的terminal
從這邊可以看出來:只要放入BG,然後用不會產生SIGHUP 的方式離開shell,就可保持job持續執行。因為shell如果不是收到SIGHUP,而只是正常離開的話,就不會主動終結BG jobs(在bash底下,可額外透過設定huponexit選項決定正常離開時是否發送SIGHUP給非FG jobs),若沒有主動終結,BG job便自然會被reparent給init。
我作了幾個實驗,確認BG job的確都會活著(並且被reparent給init):
1. 開啟GUI terminal,執行一個 for(;;); 並推到背景(用&的方式),然後鍵入exit離開。
2. 在GUI terminal下開ssh session,執行一個 for(;;); 並推到背景(用&的方式),然後鍵入exit離開。
3. 用putty開ssh session,執行一個 for(;;); 並推到背景(用&的方式),然後關閉putty(看來putty被關閉會讓shell正常離開)。
然後用關閉GUI terminal的方式或直接用kill送SIGHUP的方式給shell,的確連BG job都會掛。但我試不出底下此種情形:
1. Terminal driver偵測到 “disconnect”
忘記寫結論了 :P
回覆刪除如果你要BG jobs離開session後繼續執行,需確認以下條件:
1. 你沒有設定shell正常離開後會終結非FG jobs
2. 需使用不會觸發SIGHUP的方式離開session
或者直接使用disown或nohup,明確指定持續執行。
我覺得事情想太複雜了, 需要離開 shell 並且確保工作還是繼續執行就 nohup 丟下去做就好, 去顧慮 shell 設定或有沒有 SIGHUP 沒有什麼太大意義.
回覆刪除沒錯,但我想知道的是為何有此不一致現象:P
回覆刪除從這個問題不只了解以前錯誤的認知(以為離開後bg job也一定會收到sighup),還將shell對job control的處理摸了一遍,練從難處練,用從易處用 :-)