覆盖进程映像



假设我们正在运行一个程序,并且想要从当前程序运行另一个程序。这是可能的吗?如果不实现覆盖进程映像的概念,为什么不可能?这样是可以的,但是当前正在运行的程序呢,它还能运行吗?这怎么可能,因为我们用新程序覆盖了当前程序。如果我想运行这两个程序而不丢失当前正在运行的程序,该怎么办,这可能吗?是的,这是可能的。

创建一个子进程,以便我们有一个父进程和一个新创建的子进程。我们已经在父进程中运行了当前程序,因此在子进程中运行新创建的进程。这样,我们就可以从当前程序运行另一个程序。不仅可以运行单个程序,还可以通过创建多个子进程来从当前程序运行任意数量的程序。

让我们以以下程序为例。

/* 文件名: 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;
}

上述程序将用 helloworld 覆盖 execl_test 的进程映像。这就是 execl_test 的进程映像代码 (printf()) 未执行的原因。

编译和执行步骤

Hello World

现在,我们将从一个程序(即 execl_run_two_prgms.c)运行以下两个程序。

  • Hello World 程序 (helloworld.c)

  • 打印 1 到 10 的 while 循环程序 (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;
}

注意 - 放置 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 循环程序 (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;
}

以下是 execl_run_two_prgms.c 程序的子进程调用的 helloworld.c 程序。

/* 文件名: helloworld.c */

#include<stdio.h>

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

以下是 execl_run_two_prgms.c 程序的父进程调用的 while_loop.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)中提到的新进程覆盖当前正在运行的进程映像。如果需要将任何参数传递给新的进程映像,则将通过“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[]) 和其他参数的问题。

广告