1. 程式人生 > >Linux job control

Linux job control

Linux 系統中有一個 job control 的概念,本文簡單介紹什麼是 job,以及常見的 job control 命令。本文中演示部分使用的環境為 ubuntu 18.04。

程序組(job)

執行一個命令會建立一個或多個程序,這些程序被稱為一個程序組(process group)。程序組中包含一個或多個程序,每個程序都會屬於一個程序組,程序組也叫 job。

每個程序組都有一個領頭程序(process group leader),領頭程序的 PID 就是程序組的 ID(process group ID,PGID),我們可以通過 ps 命令檢視程序的 PGID:

$ ps -o pid,ppid,pgid,comm | cat

紅框中的兩個程序屬於同一程序組(通過管道符連線的程序屬於相同的程序組)。這個程序組中的領頭程序為 16823,因此它的 PID 成了程序組的 PGID。我們可以通過下圖來理解這幾個程序之間的關係:

領頭程序可以先退出,這時程序組依然存在並且 PGID 也不會發生變化。在程序組中的所有程序都退出後,程序組的證明週期結束。
將程序劃分到程序組中的主要原因是可以對它們進行統一的管理,說白了就是同時發訊號給組內的所有程序,這就是我們接下來要介紹的 job 管理。

Job 管理

有了前面 job 的概念(程序組),接下來我們介紹如何管理 job。
jobs 命令
使用 vim 開啟檔案 test.txt,然後按下 ctrl + z,此時 vim 進入了後臺:

輸出的第一列方括號中的數字表示 jobID,第二列 Stopped 表示 job 當前的狀態,第三列則表示該 job 執行的命令。
使用 jobs 命令可以檢視當前會話中的的所有 jobs,此時執行 jobs 命令,輸出的結果和上面一樣:

& 符
在命令的後面加上 & 符號,可以直接讓 job 執行在後臺:

$ sleep 1000 &

sleep 命令的 jobID 為 2,狀態為 Running。

fg 命令
fg 命令是 foreground 的縮寫。命令格式為 fg %n,它把當前或指定 ID 的 job 放到前臺。下面我們操作一次 job 2:

$ fg %2

此時 sleep 命令執行在前臺,通過 ctrl + z 我們可以再次把它送回後臺:

請注意此時 sleep 命令的狀態已經變成了 Stopped。

ctrl + z
嚴格來說 ctrl + z 並不是一個 job 管理命令,它只是向當前程序傳送一個 SIGSTOP 訊號,該訊號使程序進入暫停(stopped)狀態,也就是掛起程序,此狀態下,程序狀態會被系統儲存,此程序會被放置到作業佇列中去,從而讓出終端。使用 ctrl + z 我們可以暫停正在佔用終端的程序而不結束它,然後我們可以使用終端命令來操作此程序。

bg 命令
bg 命令是 background 的縮寫,命令格式為 bg %n,bg 命令和 ctrl + z 配合可以把前臺命令切換到後臺去執行。比如剛才我們通過 ctrl + z 把 sleep 命令切到了後臺,但變成了 Stopped 狀態,此時執行 bg %2 命令可以讓 sleep 命令繼續在後臺執行:

kill 命令
kill 命令負責向程序傳送訊號,當然它也可以向 job 傳送訊號,在 jobID 前面新增 % 就可以了。比如 SIGCONT 是喚醒一個掛起的程序,所以我們也可以使用下面的命令把處於 Stooped 狀態的 sleep 命令喚醒:

殺死程序

有時候使用 ctrl + c 無法殺死一個正在執行的前臺程序,這是因為 ctrl + c 的本質是向程序傳送 SIGINT 訊號。SIGINT 是用來終止程序的,但是這是一個可以被忽略的訊號,如果程式忽略了它,我們就無法通過 ctrl + c 來終止該程序。

此時我們可以先使用 ctrl + z 把程序切換到後臺,然後使用 kill %n(n 為程序的 jobID)來終止程序。kill 命令預設向程序傳送 SIGTERM 訊號,程式一般會在 SIGTERM 訊號的處理函式中正常地終止程式並執行資源清理工作。既然 SIGTERM 訊號能夠被程式處理,那麼它也能夠被忽略,所以也無法通過這種方式結束那些頑固的程序。

殺死程序的終極手段是 kill -SIGKILL PID(kill -9 PID)。SIGKILL 訊號是不能被忽略的,所以這一招肯定管用。但是由於它過於強硬,使用這種方式殺死程序後往往會有後遺症,比如程序使用的資源沒有在退出前清理乾淨,常見的例子是用這種方法殺死 vim 程序後會遺留下 .swp 檔案。

暫停 tail 命令的輸出

我們一般會使用 tail -f 命令檢視實時的日誌,但很多程式產生日誌的速度非常快以至於我們跟不上節奏。此時使用
ctrl + s 命令可以暫停日誌輸出到終端,這樣我們就可以仔細的分析當前終端中顯示的日誌。如果要接著輸出日誌,可以使用 ctrl + q 命令恢復日誌的輸出。
這兩個命令的原理是:
ctrl + s 會告訴終端暫停,阻塞所有讀寫操作,即不轉發任何資料,只有按了 ctrl + q 後,才會繼續。這個功能應該是歷史遺留的產物,以前終端和伺服器之間沒有流量控制功能,所以有可能伺服器傳送資料過快,導致終端處理不過來,於是需要這樣一個命令告訴伺服器不要再發了,等終端處理完了後再通知伺服器繼續。

參考:
Job Con