其實有時想想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] <defunct>
同樣通過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 則出現了守護進程!