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