進程間關係
進程組
每個進程都有自己的進程ID,除此之外,每個進程也都屬於一個進程組。
進程組是一個進程或者多個進程的集合。
通常他們和同一個作業有聯繫,可以接受來自同一個終端的信號。
每一個進程組都有一個組ID,這個ID就是該進程組組長的進程ID
組長進程可以創建一個進程組,並創建該組中的進程。
當一個進程組中的所有進程死亡時,該進程組纔會終止。
當一個進程組的組長死亡時,只要有其他進程存在,則該進程組存在。並且組ID仍是已故的組長進程ID。
作業
Shell通過前臺和後臺來分別控制前臺作業和後臺作業。這稱爲作業控制
Shell可以同時運行一個前臺作業和多個後臺作業。
一個作業可以由多個進程構成
作業和進程組的區別
當一個作業H中的某個進程A創建了一個子進程後B,這個進程B不屬於作業H;然而進程A和進程B都屬於同一個進程組
當前臺作業運行結束後,Shell就把自己提到前臺。如果前臺作業的某個子進程還沒有終止,則它自動變爲後臺進程
一般情況下,作業和進程組可以不做區分,但是我們要知道他們的不同之處是什麼。
查看後臺作業
jobs
將前臺作業提至後臺
bg 1(作業號) 先要contrl C終止後臺作業
將後臺作業提至前臺
fg 1(作業號)
區別驗證
fork出一個子進程後,如果將父進程退出,則前臺作業結束
子進程會以後臺進程的身份繼續運行
此時,我們用Ctrl+C無法終止該子進程(因爲CTRL+C只可以終止前臺作業)
代碼
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
pid_t pid = fork();//創建子進程
while(1)
{
if(pid < 0)
{
perror("fork");
return -1;
}
else if(pid == 0)
{
printf("子進程在運行\n");
sleep(1);
}
else
{
printf("父進程結束\n");
exit(0);
}
}
return 0;
}
運行結果
會話
會話(Session)是一個或多個進程組的集合。
一個會話可以有一個控制終端。
這通常是登陸到其上的終端設備(在終端登陸情況下)或僞終端設備(在網絡登陸情況下)。
建立與控制終端連接的會話首進程被稱爲控制進程。
一個會話中的幾個進程組可被分爲一個前臺進程組以及一個或多個後臺進程組。
所以一個會話中,應該包括控制進程(會話首進程),一個前臺進程組和任意後臺進程組。
新打開一個終端即新建立一個會話的過程。關閉一個終端,即關閉一次會話 ,其中所有的作業,進程組都不存在了。
proc1 | proc2 | proc3 &
proc4 | proc5
其中proc1與proc2和proc3屬於同一個後臺進程組,proc4和proc5屬於同一個前臺進程組
Shell本身屬於一個單獨的進程組。
這些進程組的控制終端相同,它們同屬於一個會話,當用戶在控制終端輸入特殊的控制鍵(如Ctrl+C,產生SIGINT,Ctrk+,產生SIGQUIT,Ctrl+Z,
產生SIGTSTP),內核發送相應的信號給前臺進程組中的所有進程。
終端
終端的基本概念
在UNIX系統中,用戶通過終端登錄系統後得到一個Shell進程,這個終端成爲Shell進程的控制終端 (Controlling Terminal)
控制終端是保存在PCB中的信息,而我們知道fork會複製PCB中的信息,因此由Shell進程啓動的其它進程的控制終端也是這個終端。
默認情況 下(沒有重定向)
每個進程的標準輸入、標準輸出和標準錯誤輸出都指向控制終端,進程從標準輸入讀也就是讀用戶的鍵盤輸入,進程往標準輸出或標準錯誤輸出寫也就是輸出到顯示器上。
此外在控制終端輸入一些特殊的控制鍵可以給前臺進程發信號,例如Ctrl-C表示SIGINT,Ctrl-\表示SIGQUIT。
如何查看終端
每個進程都可以通過一個特殊的設備文件/dev/tty訪問它的控制終端。 ttyname函數可以由文件描述符查出對應的文件名,該文件描述符必須指向一個終端設備而不 能是任意文件。