1、進程組
每個進程除了自己本身的ID之外,還屬於一個進程組。進程組(Process Group)是一個或多個進程的集合。
- 進程組ID等於組長進程的進程ID,組長進程可以創建一個進程組
- 每個進程組都有一個組長進程,如果組長進程終止,只要該進程組內還存在至少一個進程,則該進程組就存在,與其組長進程是否終止無關
進程組通常與作業相關聯,同組內的進程可以接收來一同一終端的同一信號
創建一個前臺進程組
注意:我們在前臺執行的都是一個進程組或者說是作業(./可執行文件
產生的是一個作業/進程組),而不是單獨的進程
前面信號機制中所說的Ctrl-C
等信號終止的是前臺進程組
重新開啓一個終端查看當前的前臺進程信息
紅圈表示的PGID
就是進程組ID的意思
剛纔創建的前臺進程組中的進程有着同樣的進程組ID:32585
在按下`Ctrl-C`後,該進程組被直接終止
ps
選項:
a
:不僅列當前用戶的進程,也列出所有其他用戶的進程x
:表示不僅列出控制終端的進程,也列出所有無控制終端的進程j
:表示列出與作業控制相關的信息
2、作業
上面說過,我們在進行./可執行文件
操作時產生的是一個作業或進程組,而不是單獨的進程。一個前臺作業可以由多個進程組成,後臺進程也是如此,後臺作業可以同一時間存在多個,前臺作業在一個終端下只能存在一個。
作業(Job)和進程組的區別:如果作業中的某個進程又創建了子進程,子進程不屬於該作業,但是屬於該進程組
下面用一段代碼解釋兩者區別
#include <stdio.h>
#include <unistd.h>
int main()
{
pid_t pid = fork();
int i = 5;
if(pid < 0)
{
perror("fork");
return -1;
}else if(pid == 0)
{//子進程
while(1)
{
//子進程一直打印該語句
printf("I am Running,I am child %d \n",getpid());
sleep(1);
}
}else{
//父進程打印完五秒後退出
while(i)
{
printf("I am father, %d \n",i--);
sleep(1);
}
}
return 0;
}
- 執行
a.out
後,產生了一個前臺作業,shell被切換到後臺,此時不可以接收命令,五秒後,父進程退出,紅線畫出的命令提示框表示shell又被切換到了前臺,可以接收命令,但是剛纔創建的子進程在後臺仍持續在打印消息,可以看出該子進程不屬於剛纔的作業,不然應該隨父進程一併退出纔對
- 這是之後又執行了一次並在另一個終端下查看的結果,可以看出父進程和子進程是同屬與一個進程組的,父進程退出後,子進程仍屬於這個進程組,但是變成了孤兒進程,並被1號進程回收,想要它不再向屏幕打印消息,直接用
kill -9 +進程ID
殺死就好
剛纔演示中可以看出,shell在運行前臺作業時,它會自動跳到後臺,所以我們在執行自己的程序時,shell是無法接收用戶輸入的命令的。一但前臺作業結束後,shell又被切換到了前臺。
前臺作業與後臺作業
- 前臺作業可以接收用戶的命令,也可以輸出結果,但一個終端下只能執行一個前臺作業,後臺作業可以有多個
- 後臺作業只可以輸出結果,不可以接收用戶輸入,Linux下剛纔演示過了,Windows下同樣也如此,比如我們在做其他工作是,後臺可以掛起QQ,可以播放音樂,我們還可以把屏幕分開,一半放視頻,一半寫作業(我經常這麼幹,哈哈),但是你每次只能操作一個界面,不可能又去控制視頻播放,同時又把歌曲切換了。
‘&’
:加在執行文件的後面,表示將該作業放到後臺執行
jods
:顯示當前後臺作業
fg 1
:將1號作業放到前臺執行,這時shell就會被切換到後臺
3、會話
會話(Session)是一個或多個進程組的集合。
一個會話應該中,應該包括控制進程(會話首進程),一個前臺進程和任意後臺進程組
- 一個會話可以有一個控制終端。這通常是登陸到其上的終端設備(在終端登陸情況下)或僞終端設備(在網絡登陸情況下)。
- 建立與控制終端連接的會話首進程被稱爲控制進程,一般是bash解釋器。
- 一個會話中的幾個進程組可被分爲一個前臺進程組以及多個後臺進程組。
啓用剛纔的例子
SID
:會話ID:32605
,可以看出一個進程組的所有進程都屬於這個會話,其實這個終端下執行的所有進程都屬於該會話(守護進程除外,最下面的SID爲702的即爲守護進程,守護進程自成會話)
該進程組的所有進程又有同樣的父進程32605
,我們來看一下該進程是誰
果不其然,該進程就是我們的bash,會話首進程。會話ID也就是我們的會話首進程的進程ID。