ภาพกระบวนการซ้อนทับ

สมมติว่าเรากำลังรันโปรแกรมและต้องการเรียกใช้โปรแกรมอื่นจากโปรแกรมปัจจุบัน เป็นไปได้หรือไม่ ทำไมไม่ถ้าเราใช้แนวคิดของการซ้อนทับภาพกระบวนการ ไม่เป็นไร แต่สิ่งที่เกี่ยวกับโปรแกรมที่กำลังทำงานอยู่ในปัจจุบันสามารถรันได้ด้วย เป็นไปได้อย่างไรเนื่องจากเราวางทับโปรแกรมปัจจุบันด้วยโปรแกรมใหม่ จะทำอย่างไรถ้าฉันต้องการเรียกใช้สองโปรแกรมโดยไม่สูญเสียโปรแกรมที่กำลังทำงานอยู่ในปัจจุบันเป็นไปได้หรือไม่? ใช่มันเป็นไปได้

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

ให้เราพิจารณาโปรแกรมต่อไปนี้เป็นตัวอย่าง

/ * ชื่อไฟล์: helloworld.c * /

#include<stdio.h>

void main() {
   printf("Hello World\n");
   return;
}

/ * ชื่อไฟล์: execl_test.c * /

#include<stdio.h>
#include<unistd.h>

void main() {
   execl("./helloworld", "./helloworld", (char *)0);
   printf("This wouldn't print\n");
   return;
}

โปรแกรมด้านบนจะซ้อนทับภาพกระบวนการของ execl_test ด้วย helloworld นั่นคือเหตุผลรหัสภาพกระบวนการของ execl_test (printf ()) จะไม่ทำงาน

ขั้นตอนการรวบรวมและดำเนินการ

Hello World

ตอนนี้เราจะเรียกใช้สองโปรแกรมต่อไปนี้จากโปรแกรมหนึ่งนั่นคือ execl_run_two_prgms.c

  • โปรแกรม Hello World (helloworld.c)

  • ในขณะที่โปรแกรมวนซ้ำเพื่อพิมพ์ตั้งแต่ 1 ถึง 10 (while_loop.c)

/ * ชื่อไฟล์: while_loop.c * /

/* Prints numbers from 1 to 10 using while loop */
#include<stdio.h>

void main() {
   int value = 1;
   while (value <= 10) {
      printf("%d\t", value);
      value++;
   }
   printf("\n");
   return;
}

ต่อไปนี้เป็นโปรแกรมสำหรับเรียกใช้สองโปรแกรม (หนึ่งโปรแกรมจากเด็กและอีกโปรแกรมจากผู้ปกครอง)

/ * ชื่อไฟล์: execl_run_two_prgms.c * /

#include<stdio.h>
#include<unistd.h>

void main() {
   int pid;
   pid = fork();
   
   /* Child process */
   if (pid == 0) {
      printf("Child process: Running Hello World Program\n");
      execl("./helloworld", "./helloworld", (char *)0);
      printf("This wouldn't print\n");
   } else { /* Parent process */
      sleep(3);
      printf("Parent process: Running While loop Program\n");
      execl("./while_loop", "./while_loop", (char *)0);
      printf("Won't reach here\n");
   }
   return;
}

Note - วางการโทร sleep () เพื่อให้แน่ใจว่ากระบวนการย่อยและพาเรนต์ทำงานตามลำดับ (อย่าให้ผลลัพธ์ทับซ้อนกัน)

ขั้นตอนการรวบรวมและดำเนินการ

Child process: Running Hello World Program
This wouldn't print
Parent process: Running While loop Program
Won't reach here

ตอนนี้เราจะเรียกใช้สองโปรแกรมจากโปรแกรมหนึ่งเช่น execl_run_two_prgms.c โปรแกรมเดียวกับด้านบน แต่มีอาร์กิวเมนต์บรรทัดคำสั่ง ดังนั้นเรากำลังเรียกใช้สองโปรแกรมคือ helloworld.c ในกระบวนการลูกและโปรแกรม while_loop.c ในกระบวนการหลัก มีดังต่อไปนี้ -

  • โปรแกรม Hello World (helloworld.c)

  • ในขณะที่โปรแกรมวนซ้ำเพื่อพิมพ์จาก 1 ถึง num_times_str ตามอาร์กิวเมนต์บรรทัดคำสั่ง (while_loop.c)

โปรแกรมนี้ดำเนินการอย่างกว้าง ๆ ดังต่อไปนี้ -

  • สร้างกระบวนการย่อย

  • กระบวนการย่อยเรียกใช้โปรแกรม helloworld.c

  • กระบวนการต้นทางรันโปรแกรม while_loop.c ส่งผ่านค่าอาร์กิวเมนต์บรรทัดคำสั่งเป็นอาร์กิวเมนต์ไปยังโปรแกรม หากไม่ผ่านอาร์กิวเมนต์บรรทัดคำสั่งค่าดีฟอลต์จะถือเป็น 10 มิฉะนั้นจะใช้ค่าอาร์กิวเมนต์ที่กำหนด ค่าอาร์กิวเมนต์ควรเป็นตัวเลข รหัสจะไม่สามารถตรวจสอบได้หากระบุเป็นตัวอักษร

/ * ชื่อไฟล์: execl_run_two_prgms.c * /

#include<stdio.h>
#include<string.h>
#include<unistd.h>

void main(int argc, char *argv[0]) {
   int pid;
   int err;
   int num_times;
   char num_times_str[5];
   
   /* In no command line arguments are passed, then loop maximum count taken as 10 */
   if (argc == 1) {
      printf("Taken loop maximum as 10\n");
      num_times = 10;
      sprintf(num_times_str, "%d", num_times);
   } else {
      strcpy(num_times_str, argv[1]);
      printf("num_times_str is %s\n", num_times_str);
      pid = fork();
   }
   
   /* Child process */
   if (pid == 0) {
      printf("Child process: Running Hello World Program\n");
      err = execl("./helloworld", "./helloworld", (char *)0);
      printf("Error %d\n", err);
      perror("Execl error: ");
      printf("This wouldn't print\n");
   } else { /* Parent process */
      sleep(3);
      printf("Parent process: Running While loop Program\n");
      execl("./while_loop", "./while_loop", (char *)num_times_str, (char *)0);
      printf("Won't reach here\n");
   }
   return;
}

ต่อไปนี้เป็นโปรแกรม helloworld.c ที่เรียกจากกระบวนการลูกของโปรแกรม execl_run_two_prgms.c

/ * ชื่อไฟล์: helloworld.c * /

#include<stdio.h>

void main() {
   printf("Hello World\n");
   return;
}

ต่อไปนี้เป็นโปรแกรม while_loop.c ที่เรียกจากกระบวนการหลักของโปรแกรม execl_run_two_prgms.c อาร์กิวเมนต์ของโปรแกรมนี้ถูกส่งผ่านจากโปรแกรมที่รันเช่น execl_run_two_prgms.c

/ * ชื่อไฟล์: while_loop.c * /

#include<stdio.h>

void main(int argc, char *argv[]) {
   int start_value = 1;
   int end_value;
   if (argc == 1)
   end_value = 10;
   else
   end_value = atoi(argv[1]);
   printf("Argv[1] is %s\n", argv[1]);
   while (start_value <= end_value) {
      printf("%d\t", start_value);
      start_value++;
   }
   printf("\n");
   return;
}

ขั้นตอนการรวบรวมและดำเนินการ

Taken loop maximum as 10
num_times_str is 10
Child process: Running Hello World Program
Hello World
Parent process: Running While loop Program
Argv[1] is 10
1 2 3 4 5 6 7 8 9 10
Taken loop maximum as 15
num_times_str is 15
Child process: Running Hello World Program
Hello World
Parent process: Running While loop Program
Argv[1] is 15
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

ตอนนี้ให้เราดูฟังก์ชันไลบรารีที่เกี่ยวข้องกับภาพซ้อนทับ

#include<unistd.h>

int execl(const char *path, const char *arg, ...);

ฟังก์ชันนี้จะซ้อนทับอิมเมจกระบวนการทำงานปัจจุบันด้วยกระบวนการใหม่ดังที่กล่าวไว้ในอาร์กิวเมนต์พา ธ และอาร์กิวเมนต์ หากอาร์กิวเมนต์ใด ๆ จำเป็นต้องส่งผ่านไปยังอิมเมจกระบวนการใหม่สิ่งนั้นจะถูกส่งผ่านอาร์กิวเมนต์ "arg" และอาร์กิวเมนต์สุดท้ายควรเป็น NULL

ฟังก์ชันนี้จะส่งคืนค่าในกรณีที่เกิดข้อผิดพลาดเท่านั้น ขั้นตอนการซ้อนภาพการโทรที่เกี่ยวข้องมีดังต่อไปนี้ -

int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);

การเรียกเหล่านี้จะกล่าวถึงการส่งผ่านอาร์กิวเมนต์บรรทัดคำสั่ง (argv []) ตัวแปรสภาพแวดล้อม (envp []) และพารามิเตอร์อื่น ๆ