其實有時想想linux內核的設計也蘊含着很多人生哲學,在linux中有這麼幾個特殊進程中,我們一開始見到它們的名字可能還會覺得很詫異,但在瞭解完了原理後,我們仔細想想,這樣的命名也不無道理!下面我就給大家分別介紹一下這三種特殊的進程!
1.孤兒進程
如果父進程先退出,子進程還沒退出那麼子進程將被 託孤給init進程,這是子進程的父進程就是init進程(1號進程).其實還是很好理解的.
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <signal.h>
int main(void)
{
pid_t pid ;
signal(SIGCHLD,SIG_IGN);
printf("before fork pid:%d\n",getpid());
int abc = 10;
pid = fork();
if(pid == -1)
{
perror("tile");
return -1;
}
if(pid > 0) //父進程先退出
{
abc++;
printf("parent:pid:%d \n",getpid());
printf("abc:%d \n",abc);
sleep(5);
}
else if(pid == 0){ //值進程後退出,被託付給init進程
abc++;
printf("child:%d,parent: %d\n",getpid(),getppid());
printf("abc:%d",abc);
sleep(100);
}
printf("fork after...\n");
}
before fork pid:27709
parent:pid:27709
abc:11
child:27710,parent: 27709
fork after…
disda 27710 1 0 10:47 pts/1 00:00:00 ./review
disda 27713 25948 47 10:47 pts/3 00:00:00 ps -ef
我們執行程序後由於子進程進入sleep(100),而父進程先退出.通過ps -ef命令我們可以知道,此時27710號進程的父進程編程了1號進程.也就是我們所說的init進程.
2.殭屍進程
如果我們瞭解過linux進程狀態及轉換關係,我們應該知道進程這麼多狀態中有一種狀態是僵死狀態,就是進程終止後進入僵死狀態(zombie),等待告知父進程自己終止,後才能完全消失.但是如果一個進程已經終止了,但是其父進程還沒有獲取其狀態,那麼這個進程就稱之爲殭屍進程.殭屍進程還會消耗一定的系統資源,並且還保留一些概要信息供父進程查詢子進程的狀態可以提供父進程想要的信息.一旦父進程得到想要的信息,殭屍進程就會結束.
int main(void)
{
pid_t pid ;
//signal(SIGCHLD,SIG_IGN);
printf("before fork pid:%d\n",getpid());
int abc = 10;
pid = fork();
if(pid == -1)
{
perror("tile");
return -1;
}
if(pid > 0)
{
abc++;
printf("parent:pid:%d \n",getpid());
printf("abc:%d \n",abc);
sleep(20);
}
else if(pid == 0){
abc++;
printf("child:%d,parent: %d\n",getpid(),getppid());
printf("abc:%d",abc);
exit(0);
}
printf("fork after...\n");
disda 27881 23047 0 11:12 pts/1 00:00:00 ./fork01
disda 27882 27881 0 11:12 pts/1 00:00:00 [fork01]
同樣通過ps -ef我們可以得知進程信息和進程pid,可以看到子進程就是處於defunct狀態.這時我們肯定想要怎麼才能避免殭屍進程呢?看程序被我註釋的那句signal(SIGCHLD,SIG_IGN),加上就不會出現殭屍進程了.那我們就加點篇幅講一下爲什麼就可以避免殭屍進程呢?
這是signal()函數的聲明sighandler_t signal(int signum, sighandler_t handler),我們可以得出,signal函數的第一個函數是Linux支持的信號,第二個參數是對信號的操作 ,是系統默認還是忽略或捕獲.我們這是就可以知道signal(SIGCHLD,SIG_IGN)是選擇對子程序終止信號選擇忽略,這是殭屍進程就是交個內核自己處理,並不會產生殭屍進程.
3.守護進程
同樣我們需要了解一下什麼是守護進程,守護進程就是在後臺運行,不與任何終端關聯的進程,通常情況下守護進程在系統啓動時就在運行,它們以root用戶或者其他特殊用戶(apache和postfix)運行,並能處理一些系統級的任務.習慣上守護進程的名字通常以d結尾(sshd),但這些不是必須的.
下面介紹一下創建守護進程的步驟
- 調用fork(),創建新進程,它會是將來的守護進程.
- 在父進程中調用exit,保證子進程不是進程組長
- 調用setsid()創建新的會話區
- 將當前目錄改成跟目錄(如果把當前目錄作爲守護進程的目錄,當前目錄不能被卸載他作爲守護進程的工作目錄)
- 將標準輸入,標註輸出,標準錯誤重定向到/dev/null
#include <sys/types.h>
#incldue <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#incldue <unistd.h>
#include <linux/fs.h>
int main(void)
{
pid_t pid;
int i;
pid = fork(); //創建一個新進程,將來會是守護進程
if(pid == -1)
{
return -1;
}
else if(pid != 0){ //父進程調用exit,保證子進程不是進程組長
exit(EXIT_SUCCESS);
}
if(setsid() == -1) //創建新的會話區
{
return -1;
}
if(chdir("/") == -1) //將當前目錄改成根目錄
{
return -1;
}
for(i = 0;i < NR_OPEN;i++)
{
close(i);
}
open("/dev/null",O_RDWR); 重定向
dup(0);
dup(0);
return 0;
}
disda 26217 1 0 06:59 ? 00:00:00 ./dm01_demon 則出現了守護進程!