กระบวนการอื่น ๆ

จนถึงตอนนี้เราได้พูดคุยเกี่ยวกับกระบวนการการสร้างกระบวนการแม่และลูก ฯลฯ การสนทนาจะไม่สมบูรณ์หากไม่พูดถึงกระบวนการอื่น ๆ ที่เกี่ยวข้องเช่นกระบวนการเด็กกำพร้ากระบวนการซอมบี้และกระบวนการภูต

กระบวนการเด็กกำพร้า

ตามที่ระบุโดยชื่อเด็กกำพร้าหมายถึงกระบวนการที่ไม่มีผู้ปกครอง เมื่อเรารันโปรแกรมหรือแอ็พพลิเคชันกระบวนการหลักสำหรับแอ็พพลิเคชันคือเชลล์ เมื่อเราสร้างกระบวนการโดยใช้ fork () กระบวนการที่สร้างขึ้นใหม่คือกระบวนการลูกและกระบวนการที่สร้างลูกคือกระบวนการแม่ ในทางกลับกันกระบวนการหลักของสิ่งนี้คือเชลล์ แน่นอนว่าพาเรนต์ของกระบวนการทั้งหมดคือกระบวนการเริ่มต้น (Process ID → 1)

ข้างต้นเป็นสถานการณ์ปกติอย่างไรก็ตามจะเกิดอะไรขึ้นถ้ากระบวนการหลักออกก่อนกระบวนการย่อย ผลลัพธ์คือตอนนี้กระบวนการย่อยกลายเป็นกระบวนการเด็กกำพร้า แล้วสิ่งที่เกี่ยวกับพาเรนต์พาเรนต์ใหม่คือพาเรนต์ของโปรเซสทั้งหมดซึ่งไม่มีอะไรเลยนอกจากกระบวนการเริ่มต้น (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

กระบวนการ Daemon

กล่าวง่ายๆคือกระบวนการที่ไม่มีเชลล์หรือเทอร์มินัลที่เกี่ยวข้องเรียกว่ากระบวนการดีมอน ทำไมจึงจำเป็น? นี่คือกระบวนการที่ทำงานอยู่เบื้องหลังเพื่อดำเนินการตามช่วงเวลาที่กำหนดไว้ล่วงหน้าและตอบสนองต่อเหตุการณ์บางอย่าง กระบวนการ daemon ไม่ควรมีการโต้ตอบกับผู้ใช้เนื่องจากรันเป็นกระบวนการเบื้องหลัง

กระบวนการภายใน Linux daemon มักจะลงท้ายด้วยตัวอักษร“ d” เช่น Kernel Daemons (ksoftirqd, kblockd, kswapd ฯลฯ ), Printing Daemons (cupsd, lpd ฯลฯ ), File Service Daemons (smbd, nmbd เป็นต้น) , daemons ฐานข้อมูลการดูแลระบบ (ypbind, ypserv ฯลฯ ), Daemons ไปรษณีย์อิเล็กทรอนิกส์ (sendmail, popd, smtpd ฯลฯ ), Remote Login และ Command Execution Daemons (sshd, in.telnetd ฯลฯ ), Booting and Configuration Daemons (dhcpd , udevd ฯลฯ ), กระบวนการเริ่มต้น (init), cron daemon, atd daemon ฯลฯ

ตอนนี้ให้เราดูวิธีสร้างกระบวนการภูต ต่อไปนี้เป็นขั้นตอน -

Step 1- สร้างกระบวนการลูก ตอนนี้เรามีสองกระบวนการ - กระบวนการหลักและกระบวนการลูก

โดยปกติลำดับชั้นของกระบวนการคือ SHELL → PARENT PROCESS → CHILD PROCESS

Step 2- ยุติกระบวนการหลักโดยการออก ตอนนี้กระบวนการย่อยกลายเป็นกระบวนการเด็กกำพร้าและถูกยึดครองโดยกระบวนการเริ่มต้น

ตอนนี้ลำดับชั้นคือ INIT PROCESS → CHILD PROCESS

Step 3- การเรียกการเรียกระบบ setsid () จะสร้างเซสชันใหม่หากกระบวนการเรียกไม่ใช่หัวหน้ากลุ่มกระบวนการ ตอนนี้กระบวนการโทรกลายเป็นผู้นำกลุ่มของเซสชันใหม่ กระบวนการนี้จะเป็นกระบวนการเดียวในกลุ่มกระบวนการใหม่นี้และในเซสชันใหม่นี้

Step 4 - ตั้งค่า ID กลุ่มกระบวนการและรหัสเซสชันเป็น PID ของกระบวนการโทร

Step 5 - ปิดตัวอธิบายไฟล์เริ่มต้น (อินพุตมาตรฐานเอาต์พุตมาตรฐานและข้อผิดพลาดมาตรฐาน) ของกระบวนการเนื่องจากเทอร์มินัลและเชลล์ถูกตัดการเชื่อมต่อจากแอปพลิเคชัน

/ * ชื่อไฟล์: 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