linux祖先进程,Linux下的几种特殊进程
1、Linux的登錄環(huán)境
Linux是一個多任務(wù)多用戶的操作系統(tǒng),其設(shè)計初衷: 就是要達(dá)成多用戶同時使用單個計算機大的任務(wù)。
多用戶:早期計算機資源緊張,為了讓更多的人都可以使用。
多任務(wù):服務(wù)于多用戶,同時提高計算機的吞吐量。
早期登錄就是通過啞終端連接登錄的。
早期登錄Linux模型
隨著以太網(wǎng)的發(fā)展,Linux的出現(xiàn),在進(jìn)行多用戶連接時候,充分使用了以太網(wǎng)。提高了應(yīng)用層的網(wǎng)絡(luò)服務(wù),這些網(wǎng)絡(luò)服務(wù)替代了之前的輪詢監(jiān)控串口的服務(wù)進(jìn)程。ssh相對于Telnet就是加密了,更加安全。
2、進(jìn)程組
在Linux下進(jìn)程除了具有父子關(guān)系這樣的組織關(guān)系以外,還具有分組的組織關(guān)系,任何一個進(jìn)程都需要隸屬于某個進(jìn)程組。
每一個進(jìn)程組都擁有一個獨立的進(jìn)程組編號,可以通過getpgid()方法得到。
每一個進(jìn)程組都擁有且只擁有一個組長進(jìn)程。可以通過該組長管理其組內(nèi)的其它進(jìn)程的統(tǒng)一行為。(例如:組長進(jìn)程若獲取一個特殊的信號,該信號可以傳遞給組內(nèi)所有進(jìn)程)。
進(jìn)程組ID就是該進(jìn)程組組長的進(jìn)程ID。
進(jìn)程組內(nèi)的成員都是組長的子及子孫。
3、會話
每一個進(jìn)程除了要歸屬一個進(jìn)程組以外,還需要歸屬于一個會話之中。會話的概念主要是從終端登錄到計算機之后得到的。
當(dāng)一個終端登錄到計算機之后,為了方便將不同的終端隔離開,同時又能夠充分合理的管理一個終端下產(chǎn)生的所有進(jìn)程,因此而提出了會話的概念。換句話來說,會話就是用戶登錄之后從登錄服務(wù)進(jìn)程到shell進(jìn)程所組成的集合。
從邏輯上來講,會話就控制了計算機和某一個終端的一個連續(xù)的交互過程。
一個會話通常是由多個進(jìn)程組組成的,分為兩部分(前臺進(jìn)程組、后臺進(jìn)程組)。
會話具有一個會話首進(jìn)程。操作系統(tǒng)通過會話的首進(jìn)程來管理整個會話中的所有進(jìn)程組。
(1)、前臺進(jìn)程組
是和終端服務(wù)進(jìn)程、bash進(jìn)程捆綁在一起的,和終端直接相關(guān)。那么,終端的任何操作都會影響到所有的前臺進(jìn)程組。
在shell交互環(huán)境中執(zhí)行一個命令,就會產(chǎn)生一個新的進(jìn)程來執(zhí)行這個命令,不僅如此,還會產(chǎn)生一個新的進(jìn)程組,該進(jìn)程組的組長就是被執(zhí)行命令而形成的新進(jìn)程。
前臺進(jìn)程組的最大問題就在于,需要看終端的臉色!終端只需要讓進(jìn)程組的組長停止,其內(nèi)部的所有進(jìn)程都會停止。
(2)、后臺進(jìn)程組
斷開與終端的關(guān)系(并非輸入、輸出、錯誤輸出關(guān)系),進(jìn)程組關(guān)系,不在受制于終端而存在,這種進(jìn)程與進(jìn)程組被稱之為后臺的。
后臺進(jìn)程存在的理由就是,需要常駐內(nèi)存,提供一個服務(wù)。
4、進(jìn)程組如何創(chuàng)建
創(chuàng)建一個新的進(jìn)程組的方式有2種,這2種有區(qū)別:
(1)、通過調(diào)用setpgid()能夠?qū)⒄{(diào)用該方法的當(dāng)前進(jìn)程設(shè)置為新的進(jìn)程組的組長。從而創(chuàng)建一個新的進(jìn)程。
(2)、通過調(diào)用setsid()方法來創(chuàng)建一個新的會話,從而就會出現(xiàn)新的進(jìn)程組,調(diào)用setsid()方法的進(jìn)程就會成為會話的首進(jìn)程,新進(jìn)行組的組長。
5、僵尸進(jìn)程
在Linux操作系統(tǒng)設(shè)計中,要求進(jìn)程結(jié)束的時候需要告知其父進(jìn)程該進(jìn)程的結(jié)束,父進(jìn)程也需要知道其子進(jìn)程結(jié)束的狀態(tài),這是因為父進(jìn)程有些時候需要根據(jù)子進(jìn)程結(jié)束的狀態(tài)來作一些后續(xù)的操作。
進(jìn)程的消亡:
(1)、進(jìn)程調(diào)用了exit()方法,通知操作系統(tǒng)內(nèi)存,當(dāng)前進(jìn)程想要結(jié)束自己的生命;
(2)、操作系統(tǒng)此時就會立即回收進(jìn)程的幾乎所有的主要內(nèi)容,然后告知其父進(jìn)程,它的某一個子進(jìn)程結(jié)束;
(3)、父進(jìn)程需要明確的答復(fù)操作系統(tǒng)內(nèi)核,已收到子進(jìn)程結(jié)束的消息。否則,操作系統(tǒng)內(nèi)核會一直保存該將要結(jié)束進(jìn)程的部分PCB信息。同時將進(jìn)程的狀態(tài)置為defunct。這就是僵尸進(jìn)程。
i>、僵尸進(jìn)程是不能夠被直接消除掉的。
ii>、僵尸進(jìn)程的危害: 占用PCB資源(PID資源)。
iii>、子進(jìn)程先于父進(jìn)程結(jié)束,父進(jìn)程沒有收尸,就是僵尸進(jìn)程。
其產(chǎn)生僵尸進(jìn)程的代碼如下:#include
#include
#include
int?main(void){
pid_t?pid;
pid?=?fork();
if(pid?==?0){
printf("This?is?child,?will?finish.?pid?=?%d\n",?getpid());
}else?if(pid?>?0){
while(1){
printf("This?is?father,?run?allways.?pid?=?%d?childPid?=?%d\n",?getpid(),?pid);
sleep(1);
}
}else{
perror("");
}
return?0;
}
運行結(jié)果
如何解決僵尸進(jìn)程的問題?避免僵尸進(jìn)程的產(chǎn)生。
解決僵尸進(jìn)程的根本就在于父進(jìn)程需要處理子進(jìn)程的結(jié)束。通過調(diào)用wait()函數(shù)族來進(jìn)行解決。wait會等待子進(jìn)程的結(jié)束,調(diào)用wait的進(jìn)程會阻塞,直到接受到子進(jìn)程的結(jié)束消息時才會被喚醒。父進(jìn)程等待子進(jìn)程的結(jié)束消息為SIGCHLD(17)信號。
解決僵尸進(jìn)程的代碼 :#include
#include
#include
int?main(void){
pid_t?pid;
pid?=?fork();
if(pid?==?0){
int?i;
for(i?=?0;?i?
printf("This?is?child,?will?finish.?pid?=?%d\n",?getpid());
sleep(1);
}
}else?if(pid?>?0){
int?status;
wait(&status);?//很好的處理了僵尸進(jìn)程。
printf("child?has?gone,?status?=?%d\n",?status);
while(1){
printf("This?is?father,?run?allways.?pid?=?%d?childPid?=?%d\n",?getpid(),?pid);
sleep(1);
}
}else{
perror("");
}
return?0;
}
此時就會造成父進(jìn)程一開始什么也干不了,只能等待子進(jìn)程的結(jié)束,自己才能開始運行。
僵尸進(jìn)程的解決其實是進(jìn)程回收進(jìn)程。
6、孤兒進(jìn)程
如果某一個進(jìn)程的父進(jìn)程先于自己結(jié)束,那么該進(jìn)程還有父進(jìn)程嗎?必須有,因為在Linux下所有的進(jìn)程都必須存在于整個進(jìn)程樹之中,不允許完全孤立的存在。
如果發(fā)生父進(jìn)程先于子進(jìn)程結(jié)束的情況,則將子進(jìn)程過繼給編號為1的進(jìn)程,即就是init/systemd進(jìn)程。
然而此時該進(jìn)程的進(jìn)程組關(guān)系已經(jīng)打亂。它所在的進(jìn)程組不在是其父進(jìn)程或祖先進(jìn)程。因為,此時子進(jìn)程依然保留之前的進(jìn)程組信息,但是很顯然這個進(jìn)程組與會話信息已經(jīng)不對了。
這種進(jìn)程就是孤兒進(jìn)程,失去了原有的所有進(jìn)程組與會話關(guān)系的進(jìn)程。所以也會將init/systemd進(jìn)程稱之為孤兒院進(jìn)程,因為它收養(yǎng)了很多孤兒。
因為子進(jìn)程的父進(jìn)程結(jié)束,所以其組的組長的信號就不能夠傳遞給該孩子進(jìn)程。從而使得該子進(jìn)程就脫離了原有的進(jìn)程組關(guān)系、脫離了原有的會話關(guān)系。雖然它保留了原有的進(jìn)程組和會話ID,但是已經(jīng)不起任何作用了。
產(chǎn)生孤兒進(jìn)程的代碼 :#include
#include
int?main(void){
pid_t?pid;
pid?=?fork();
if(pid?==?0){
while(1){
printf("This?is?along?child,?pid?=?%d,?pgid?=?%d?sid?=?%d\n",?getpid(),?getpgid(getpid()),
getsid(getpid()));
sleep(1);
}
}else?if(pid?>?0){
printf("This?is?father,?pid?=?%d,?pgid?=?%d?sid?=?%d\n",?getpid(),?getpgid(getpid()),?getsid(getpi
d()));
}else{
perror("");
}
return?0;
}
此時孤兒進(jìn)程產(chǎn)生,將用ctrl+c終止不下來,只能用kill PID進(jìn)行殺死該孤兒進(jìn)程了。
7、守護(hù)進(jìn)程
守護(hù)一個服務(wù),長期駐留在內(nèi)存中提供服務(wù),不能夠受制于終端。通常指的就是操作系統(tǒng)中的服務(wù)進(jìn)程。這些服務(wù)進(jìn)程通常約定其名稱最后一個字母為d。
守護(hù)進(jìn)程的另外一個名字 : 精靈進(jìn)程(demon)。
如何讓一個進(jìn)程成為守護(hù)進(jìn)程? 讓一個進(jìn)程脫離前臺進(jìn)程組關(guān)系即可(這樣就可以擺脫終端對它的控制)。
怎樣讓進(jìn)程脫離前臺進(jìn)程組? 1)、創(chuàng)建一個新的會話;2)、構(gòu)成孤兒進(jìn)程。
通常讓這兩個步驟都進(jìn)行。
守護(hù)進(jìn)程的創(chuàng)建過程:pid_t?pid;
pid?=?fork();
if(pid?==?0){
setsid();???//產(chǎn)生會話進(jìn)程
while(1){????//子進(jìn)程一直在運行,遲早會構(gòu)成孤兒進(jìn)程。
...
}
}else?if(pid?>?0){
...
exit(0);??//父進(jìn)程結(jié)束
}else{
perror();
}
8、僵尸進(jìn)程和孤兒進(jìn)程的一個關(guān)聯(lián)
init/systemd又叫做上帝進(jìn)程,一手創(chuàng)造了操作系統(tǒng)內(nèi)部的所有的進(jìn)程以外,還管理了這些僵尸進(jìn)程,幫助將其清除掉了。
如果一個進(jìn)程下產(chǎn)生了僵尸子進(jìn)程,當(dāng)該進(jìn)程結(jié)束的時候,會將僵尸進(jìn)程過繼給init/systemd進(jìn)程,然后init/systemd進(jìn)程發(fā)現(xiàn)過繼的新子進(jìn)程是僵尸進(jìn)程之后,會為其收尸,從而消除掉已經(jīng)存在的僵尸進(jìn)程。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的linux祖先进程,Linux下的几种特殊进程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: html前台检验特殊字符正则,【Qt编程
- 下一篇: java int stack_java