終端&作業控制&會話啟動過程,超級終端
進程組
每個進程除了有個進程id外,還屬於一個進程組。進程組是一個或者多個進程的集合。通常他們與同一個作業相關聯,可以接受來自同一終端的訊號。進程組id等於其進程組長id。進程組的終止與進程組長是否存在無關,只要有一個成員進程存在,那麼這個進程組就存在。
作業
shell分前後台進行控制的不是進程而是作業或者進程組。一個前台作業可以由多個進程組成,一個後台作業也可以由多個進程組成。shell可以運行一個前台作業和多個後台作業,這稱為作業控制。
作業與進程組的區別:如果一個作業中的某個進程建立了一個子進程,那麼這個子進程不屬於作業,但屬於進程組。
會話
會話是一個或者多個進程組的集合。
一個會話可以有一個控制終端。建立與控制終端串連的會話首進程被稱為控制進程。
註:通過管道方式實現一個作業任務。
前兩行:對比可以看出,兩個sleep命令的PPID(父進程id:bash),PGID(進程組ID),SID(會話ID),TTY(終端)都是相同的。
PID是不同的,他們是一個進程組中的兩個不同進程。
將之與第三行對比,發現,各個項都是不同的,特別是SID,TTY,TPGID(top PGID(前台進程組ID))都是不同的。
ps -e 或 ps -o pid,ppid,session,tpgid, comm (其中session顯示的sessionid, tpgid顯示前台進程組id, comm顯示命令名稱)
同時,我們可以驗證,SID會話ID是由每個終端進行確定的。
由這個圖我們更可以清晰的理解到,對於每一個連續的命令執行流,其進程組/作業id是相同的。會話id則是終端相關的。
#include <stdio.h>#include <unistd.h>int main(int argc, char const *argv[]){ printf("fd: %d -> %s\n",0,ttyname(0) ); printf("fd: %d -> %s\n",1,ttyname(1) ); printf("fd: %d -> %s\n",2,ttyname(2) ); return 0;}
現在我們來看終端登入的過程:
1、系統啟動時,init進程根據設定檔/etc/inittab確定需要開啟哪些終端。例如設定檔中有
這樣一行:
1:2345:respawn:/sbin/getty 9600 tty1
和/etc/passwd類似,每個欄位用用:號隔開。開頭的1是這一一行行配置的id,通常要和tty的尾碼一一致,配置tty2的那一一行行id就應該是2。第二二個欄位2345表示示運行行層級2~5都執行行這個配置。最後一個字 段/sbin/getty 9600 tty1是init進程要fork/exec的命令,開啟終端/dev/tty1,傳輸速率 是9600(傳輸速率只對串又口口和Modem終端有意義),然後提示示用使用者輸入入帳號。中間的respawn欄位表示示init進程會監視getty進程的運行行狀態,一一旦該進程終止止,init會再次fork/exec這個命令,所以 我們從終端退出登入後會再次提示示輸入入帳號。
2、getty根據命令列行參數開啟終端裝置作為它的控制終端,把文檔案描述符0、1、2都指向控制終 端,然後提示示用使用者輸入入帳號。用使用者輸入入帳號之後,getty的任務就完成了,它再執行行login程式:
execle("/bin/login", "login", "-p", username, NULL, envp);
3、如果密碼不正確,login進程終止止,init會重新fork/exec一一個getty進程。如果密碼正確,login程 序設定一一些環境變數,設定當前工工作目目錄為該用使用者的主目目錄,然後執行行Shell:
execl("/bin/bash", "-bash", NULL);
從getty開始exec到login,再exec到bash,其實都是同一一個進程,因此控制終 端沒變,文檔案描述符0、1、2也仍然指向控制終端。由於fork會複製PCB資訊,所以由Shell啟動的 其它進程也都是如此。
從會話角度講 終端開啟過程是:
1。getty或者telnetd調用setsid,設定會話id,在這個id的基礎上開啟終端,建立會話。同時建立一個進程組。且該進程是此終端下所有會話的控制終端。
2。登入過程中,進行exec替換。變為login,然後變為shell
3。當shell調用fork建立子進程進行工作時,調用setpgid將作業中的某個進程設定偽新的組進程,形成本會話內的一個作業流。
註:在作業中,如果某個進程建立新的子進程了,該子進程並不會作為作業內容而被等待。當真是作業完成時,作業就會退出。(進程組和作業的區別)。
關於作業的命令:
jobs查看當前系統執行作業
process & 將process作為後台作業執行。
bg 將作業改為後台執行
fg 將作業改為前台執行
參數的話, %1 表示作業號為1
lang@liang:~/linux/thread$ cat fsdf &[2] 6470lang@liang:~/linux/thread$ fsdf
給一個需要寫入終端的命令設定後台執行時,並不能成功。
這時我們需要設定stty tostop 禁止後台進程寫。然後才能成功