Linux守護進程基礎

來源:互聯網
上載者:User

1 守護進程中涉及到的基本概念


1.1進程組
1.1.1 進程組基本概念
進程組是一個或多個進程的集合,可以接收來自同一個終端的各種訊號。每運行一個程式或是命令都將產生一個進程組。

每個進程屬於一個進程組,而每個進程組都存在一個領頭進程(或是叫組長進程),一般進程組的第一個進程是領頭進程。領頭進程可以建立一個進程組、建立該組中的進程。領頭進程fork出的子進程也將在該進程組中,一旦子進程執行exec等退出函數就不再屬於該進程組。

 


進程組的生命週期:從建立開始到最後一個進程離開為止成為進程組的生命週期。組中最後一個進程的離開可以是終止,或加入其他進程。進程組的生命週期與組長進程是否終止無關,只要有一個進程存在,進程組的生命週期就未結束。

1.1.2 相關命令
1、查看所有進程組pid(即領頭進程的pid):ps –A –o pgrp= | sort |uniq

2、查看某個進程的進程組pid:ps –C 進程名 –o pgrp=

3、根據進程名獲得進程pid:pidof 進程名

4、根據進程pid獲得進程名:ps –aux |grep 進程pid

5、擷取某個進程的具體資訊:ps –ef |grep 進程名或進程pid

1.1.3 相關函數
#include <unistd.h>

pid_t getpgrp();    //擷取進程組pid,即進組中的領頭進程的pid,相當於調用getpgid(0)

pid_t getpid();     //擷取當前進程pid

pid_t getppid();    //擷取當前進程的父pid

pid_t getpgid();    //返回指定進程的進程組pid

int setpgid(pid_t pid, pid_t pgid); /*將pid進程的進程組id設定為pgid,如果兩個參數相等,

                                                            *則pid指定的進程變成進程組組長。如果pid是0,則進程

                                                            *組id為pgid,如果pgid是0,則進程組id為pid。*/

int setpgrp();  //將當前進程所屬的進程組的pid設定為當前進程的pid,相當於setpgid(0, 0)

1.2會話
1.2.1 會話基本概念
        一次登入形成一個會話,一個會話可包括多個進程組(www.linuxidc.com一個前台進程組和多個後台進程組),但只能有一個前台進程組。

1.2.2 相關函數
#include <unistd.h>

pid_t setsid();  

         當調用該函數的進程不是進程組的領頭進程時,該函數才能建立新的會話。函數調用成功後,調用進程成為新會話的領頭進程和新進程的領頭進程,同時進程失去控制終端。

1.3控制終端
         進程組中有領頭進程,類似地,會話中也對應有領頭進程。會話的領頭進程開啟一個終端之後,該終端就成為會話的控制終端,與控制終端建立串連的會話的領頭進程成為控制進程(session leader)。一個會話只能有一個控制終端,同時一個控制終端只能一個會話。         產生在控制端上的輸入和訊號(比如按下ctrl+c就會產生SIGINT訊號)將發送給會話的前台進程組中的所有進程。

2守護進程及其特性
1、守護進程最重要的特性是後台運行;

2、守護進程必須與其運行前的環境脫離開來。這些環境包括未關閉的檔案描述符,控制終端,會話和進程組,工作目錄等,這些環境通常是從執行它的父進程(特別是Shell)中繼承下來的。

3、守護進程可以在Linux系統啟動時從指令碼/etc/rc.d中啟動,可以由作業規划進程crond啟動,還可以由使用者終端(通常是Shell)執行。

3 守護進程編程
        針對守護進程的特性可以將普通進程改造為守護進程。

3.1後台運行特性
讓daemon在子進程中運行。

if( pid=fork() )

{

         exit(0);  //父進程結束,子進程繼續

}

3.2脫離環境
3.2.1脫離進程組、登入工作階段和控制終端
         進程組、登入工作階段和控制終端通常都是從父進程繼承下來的,為了不受它們的影響,控制終端必須將其擺脫。具體方法是調用setsid函數。

         通過if( pid=fork() ){exit(0);}將產生了子進程,能保證調用setsid的進程不是進程組中的領頭進程。當setsid調用成功後,該子進程成為新會話中的領頭進程和進程組的領頭進程,並脫離了原來的會話、進程組和控制終端。

3.2.2禁止進程開啟控制終端
if( pid=fork() )

{

         exit(0);  //該子進程結束,又產生子進程

}

         結束該子進程,產生新的子進程,此時的新子進程不是會話領頭進程,所以不能開啟控制終端。通過這種方式就能禁止進程開啟控制終端。

3.2.3脫離開啟的檔案描述符
         進程從其父進程繼承了開啟的檔案描述符。如不關閉,將會造成系統資源的浪費,同時,造成進程所在的檔案系統無法卸載以及引起其他無法預料的錯誤。

max_fd = sysconf(_SC_OPEN_MAX);

for(i = 0; i < max_fd; i++)

{

close(i);

}


3.2.4脫離當前工作目錄
進程活動時,其工作目錄所在的檔案系統不能卸載,一般需要將工作目錄切換到根目錄。對於需要作業記錄的進程將工作目錄改變到特定的目錄。

chdir(“/”);

3.2.5重設檔案的許可權掩碼 

         進程從其父進程繼承的檔案的許可權掩碼,可能會修改守護進程所建立的檔案許可權,需要將掩碼清楚。

umask(0);

3.2.6處理SIGCHLD訊號
         處理SIGCHLD訊號並不是必須的。但對於某些進程,www.linuxidc.com 特別是伺服器處理序往往在請求到來時產生子進程處理請求。如果父進程沒有等待(沒有調用wait或waitpid)子進程的結束,子進程將成為殭屍進程(Zombie Process)從而佔用系統資源。而如果父進程等待子進程結束,又將增加父進程的負擔,影響伺服器處理序的並發效能。在Linux可以將SIGCHLD設定為SIG_IGN,這樣核心在子進程結束時不會產生殭屍進程。

signal(SIGCHLD, SIG_IGN);  //屏蔽SIGCHLD訊號

         這是常用於並發伺服器提升效能的一個技巧。當伺服器處理序沒有調用wait去清理子進程而產生殭屍子進程時,如果屏蔽了SIGCHLD訊號,核心會把殭屍子進程轉交給init進程處理。

4 守護進程樣本
#include <unistd.h>    
#include <signal.h>    
#include <sys/types.h>    
#include <sys/stat.h>    
#include <stdio.h>    
#include <stdlib.h>   
  
void init_daemon()   
{   
  
         int pid;   
         int i;   
         int max_fd;  
  
   
         if(pid = fork())  
         {  
             exit(0); //父進程結束,子進程繼續   
           }   
         else if(pid < 0)  
         {  
             exit(1); //fork失敗              
           }  
  
         setsid();    
  
         if(pid = fork())  
         {  
             exit(0); //該子進程結束,又產生新子進程    
           }  
         else if(pid < 0)  
         {  
             exit(1); //fork錯誤,退出   
           }   
         
         /* 關閉開啟的檔案描述符*/   
         max_fd = sysconf(_SC_OPEN_MAX);  
  
         for(i = 0; i < max_fd; i++)  
         {   
             close(i);   
         }   
  
         /* 切換工作目錄 */   
         chdir("/tmp");   
   
  
         /* 重設檔案建立掩碼 */   
         umask(0);   
  
         return;   
  
}   
  
int main()   
{   
  
         FILE *fp = NULL;   
  
         signal(SIGCHLD, SIG_IGN);   
  
         init_daemon();   
  
         while(1)   
         {   
  
             sleep(1);  
             if((fp = fopen("/mnt/hgfs/Share/unix/test.log", "a")) != NULL)  
             {   
                 fprintf(fp, "%s\n", "test message");   
                 fclose(fp);   
             }   
         }   
  
         return 0;   
}  
編譯:gcc –o daemon daemon.c

運行:./daemon

查看守護進程:ps –ef |grep daemon

 

查看該精靈產生的檔案:

 

作者“Orion的部落格”
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.