其他程序



到目前為止,我們已經討論了程序、程序的建立、父程序和子程序等等。如果不討論其他相關程序,例如孤兒程序、殭屍程序和守護程序,這個討論將是不完整的。

孤兒程序

顧名思義,孤兒意味著沒有父程序的程序。當我們執行程式或應用程式時,應用程式的父程序是shell。當我們使用fork()建立程序時,新建立的程序是子程序,建立子程序的程序是父程序。反過來,它的父程序是shell。當然,所有程序的父程序都是init程序(程序ID → 1)。

以上是一個常見的情況,但是,如果父程序在子程序之前退出會發生什麼?結果是,子程序現在變成了孤兒程序。那麼它的父程序呢?它的新父程序是所有程序的父程序,也就是init程序(程序ID – 1)。

讓我們用下面的例子來理解這一點。

/* 檔名: orphan_process.c */

#include<stdio.h>
#include<stdlib.h>

int main() {
   int pid;
   system("ps -f");
   pid = fork();
   if (pid == 0) {
      printf("Child: pid is %d and ppid is %d\n",getpid(),getppid());
      sleep(5);
      printf("Child: pid is %d and ppid is %d\n",getpid(),getppid());
      system("ps -f");
   } else {
      printf("Parent: pid is %d and ppid is %d\n",getpid(),getppid());
      sleep(2);
      exit(0);
   }
   return 0;
}

編譯和執行步驟

UID         PID   PPID  C STIME TTY    TIME CMD
4581875  180558      0  0 09:19  ?     00:00:00 sh -c cd /home/cg/root/4581875; 
                                       timeout 10s main
4581875  180564 180558  0 09:19  ?     00:00:00 timeout 10s main
4581875  180565 180564  0 09:19  ?     00:00:00 main
4581875  180566 180565  0 09:19  ?     00:00:00 ps -f
Parent: pid is 180565 and ppid is 180564
UID         PID   PPID  C STIME TTY    TIME CMD
4581875  180567      0  0 09:19  ?     00:00:00 main
4581875  180820 180567  0 09:19  ?     00:00:00 ps -f
Child: pid is 180567 and ppid is 180565
Child: pid is 180567 and ppid is 0

殭屍程序

簡單來說,假設您有兩個程序,即父程序和子程序。父程序有責任等待子程序,然後從程序表中清理子程序的條目。如果父程序沒有準備好等待子程序,而與此同時子程序完成了它的工作並退出了會怎樣?現在,子程序將變成殭屍程序。當然,在父程序準備好之後,殭屍程序會被清理掉。

讓我們藉助一個例子來理解這一點。

/* 檔名: zombie_process.c */

#include<stdio.h>
#include<stdlib.h>

int main() {
   int pid;
   pid = fork();
   if (pid == 0) {
      system("ps -f");
      printf("Child: pid is %d and ppid is %d\n",getpid(),getppid());
      exit(0);
   } else {
      printf("Parent: pid is %d and ppid is %d\n",getpid(),getppid());
      sleep(10);
      system("ps aux|grep Z");
   }
   return 0;
}

編譯和執行步驟

UID         PID   PPID  C STIME TTY    TIME CMD
4581875  184946      0  0 09:20  ?     00:00:00 sh -c cd /home/cg/root/4581875; 
                                       timeout 10s main
4581875  184952 184946  0 09:20  ?     00:00:00 timeout 10s main
4581875  184953 184952  0 09:20  ?     00:00:00 main
4581875  184954 184953  0 09:20  ?     00:00:00 main
4581875  184955 184954  0 09:20  ?     00:00:00 ps -f
Child: pid is 184954 and ppid is 184953

守護程序

簡單來說,沒有關聯shell或終端的程序被稱為守護程序。為什麼需要這個?這些程序在後臺執行,以預定的間隔執行操作,並響應某些事件。守護程序不應該有任何使用者互動,因為它作為後臺程序執行。

內部Linux守護程序通常以字母“d”結尾,例如核心守護程序(ksoftirqd、kblockd、kswapd等)、列印守護程序(cupsd、lpd等)、檔案服務守護程序(smbd、nmbd等)、管理資料庫守護程序(ypbind、ypserv等)、電子郵件守護程序(sendmail、popd、smtpd等)、遠端登入和命令執行守護程序(sshd、in.telnetd等)、引導和配置守護程序(dhcpd、udevd等)、init程序(init)、cron守護程序、atd守護程序等。

現在讓我們看看如何建立一個守護程序。步驟如下:

步驟1 - 建立一個子程序。現在我們有兩個程序——父程序和子程序

通常的程序層次結構是 SHELL → 父程序 → 子程序

步驟2 - 透過退出終止父程序。子程序現在成為孤兒程序,並由init程序接管。

現在的層次結構是 INIT程序 → 子程序

步驟3 - 呼叫setsid()系統呼叫建立一個新的會話,如果呼叫程序不是程序組組長。現在呼叫程序成為新會話的組長。這個程序將是這個新程序組和這個新會話中唯一的程序。

步驟4 - 將程序組ID和會話ID設定為呼叫程序的PID。

步驟5 - 關閉程序的預設檔案描述符(標準輸入、標準輸出和標準錯誤),因為終端和shell現在與應用程式斷開了連線。

/* 檔名: daemon_test.c */

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdlib.h>
#include<string.h>

int main(int argc, char *argv[]) {
   pid_t pid;
   int counter;
   int fd;
   int max_iterations;
   char buffer[100];
   if (argc < 2)
   max_iterations = 5;
   else {
      max_iterations = atoi(argv[1]);
      if ( (max_iterations <= 0) || (max_iterations > 20) )
      max_iterations = 10;
   }
   pid = fork();
   
   // Unable to create child process
   if (pid < 0) {
      perror("fork error\n");
      exit(1);
   }
   
   // Child process
   if (pid == 0) {
      fd = open("/tmp/DAEMON.txt", O_WRONLY|O_CREAT|O_TRUNC, 0644);
      if (fd == -1) {
         perror("daemon txt file open error\n");
         return 1;
      }
      printf("Child: pid is %d and ppid is %d\n", getpid(), getppid());
      printf("\nChild process before becoming session leader\n");
      sprintf(buffer, "ps -ef|grep %s", argv[0]);
      system(buffer);
      setsid();
      printf("\nChild process after becoming session leader\n");
      sprintf(buffer, "ps -ef|grep %s", argv[0]);
      system(buffer);
      close(STDIN_FILENO);
      close(STDOUT_FILENO);
      close(STDERR_FILENO);
   } else {
      printf("Parent: pid is %d and ppid is %d\n", getpid(), getppid());
      printf("Parent: Exiting\n");
      exit(0);
   }
   
   // Executing max_iteration times
   for (counter = 0; counter < max_iterations; counter++) {
      sprintf(buffer, "Daemon process: pid is %d and ppid is %d\n", getpid(), getppid());
      write(fd, buffer, strlen(buffer));
      sleep(2);
   }
   strcpy(buffer, "Done\n");
   write(fd, buffer, strlen(buffer));
   
   // Can't print this as file descriptors are already closed
   printf("DoneDone\n");
   close(fd);
   return 0;
}

Parent: pid is 193524 and ppid is 193523
Parent: Exiting
4581875  193525      0  0 09:23  ?      00:00:00 main
4581875  193526 193525  0 09:23  ?      00:00:00 sh -c ps -ef|grep main
4581875  193528 193526  0 09:23  ?      00:00:00 grep main
4581875  193525      0  0 09:23  ?      00:00:00 main
4581875  193529 193525  0 09:23  ?      00:00:00 sh -c ps -ef|grep main
4581875  193531 193529  0 09:23  ?      00:00:00 grep main
廣告