您好,欢迎来到刀刀网。
搜索
您的当前位置:首页【Linux进程】进程程序替换

【Linux进程】进程程序替换

来源:刀刀网


前言

        父进程创建子进程去执行任务,执行的代码和数据,其实都是父进程的一部分,如果我们想让子进程执行全新的代码和数据,不再和父进程有任何关系怎么办?——进程程序替换,本文我们就来聊一聊进程程序替换;

程序替换的基本操作

        用fork创建子进程后执行的是父进程相同的程序,可以通过调用一种 exec 函数替换原来的程序,以执行另一个程序;

程序替换的接口

        常用的exec函数有六种:

int execl(const char *pathname, const char *arg, .../* (char  *) NULL */);

int execlp(const char *file, const char *arg, .../* (char  *) NULL */);

int execle(const char *pathname, const char *arg, .../*, (char *) NULL, char *const envp[]*/);

int execv(const char *pathname, char *const argv[]);

int execvp(const char *file, char *const argv[]);

int execve(const char *path, char *const argv[], char *const envp[]);

 注意:

  • 这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。
  • 如果调用出错则返回-1
  • 所以exec函数只有出错的返回值而没有成功的返回值

 这些函数看似很多,很复杂,但掌握了规律,使用和记忆就会简单许多;

  • l(list) : 表示参数采用列表
  • v(vector) : 参数用数组
  • p(path) : 有p自动搜索环境变量PATH
  • e(env) : 表示自己维护环境变量

 示例:

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/types.h>

extern char** environ;
int main()
{
    char* const myenv[] = {
    "MYVAL1=11111111111111",
    "MYVAL2=11111111111111",
    "MYVAL3=11111111111111",
    NULL
    };
    pid_t id = fork();
    if (id == 0)
    {
        char* const argv[] =
        {
          "ls",
          "-a",
          "-l",
          NULL
        };

        printf("pid: %d,exec command begin\n", getpid());
        // 不带p需要指定路径
        //execl("./mytest","mytest",NULL);
        //execl("/usr/bin/ls","ls","-a","-l",NULL);
        //execl("/usr/bin/python3","python3","test.py",NULL);//调用python程序
        
        // 带 e 允许调用时直接指定新程序的环境变量列表
        execle("./mytest", "mytest", "-a", "-b", NULL, myenv);

        //execle("./mytest", "mytest", "-a", "-b", NULL, environ);
        
        // 带p无需指定路径,默认从环境变量PATH中找
        //execlp("ls","ls","-a","-l",NULL);

        
        // 带 v 可以理解为以数组的方式传参
        //execv("/usr/bin/ls", argv);
        //execvp("ls", argv);
        
        printf("pid: %d,exec command end\n", getpid());
        exit(1);
    }
    else {
        // father
        pid_t rid = waitpid(-1, NULL, 0);
        if (rid > 0)
        {
            printf("wait success, rid: %d\n", rid);
        }

    }
    return 0;
}

 事实上,只有execve是真正的系统调用,其它五个函数最终都调用 execve

 这些函数之间的关系:

 程序替换的原理

          exec函数会将原进程的代码和数据进行替换(不会产生新的进程,进程PID不会变);

 注意:

进行程序替换时,并不会替换掉子进程的环境变量,替换的新程序依然默认使用从父进程继承下来的环境变量;

如果子进程想用新的环境变量,可以在程序替换时进行传递,比如:execle;带e的exec函数可以传递环境变量,调用者可以自定义环境变量表进行传递,但需要注意的是,这里传递的环境变量是覆盖式的,而不是拼接式的;

 思考:

父进程创建子进程,子进程与父进程用同一份代码,那程序替换后会不会影响父进程?

不会,程序替换时也会对代码进行写时拷贝;

程序替换后,新的代码和数据加载到内存中,那么子进程如何知道替换进来的程序从哪里执行?

执行到哪里?

如何知道执行到哪里:程序计数器(pc),是粗、CPU内部的寄存器(eip),调用哪个程序就把程序的entry(程序的入口)填到CPU内部的eip寄存器中;而程序被调度切换时,就会把寄存器中的数据(进程上下文)保存到进程的PCB中(间接保存),其中就包含eip的数据,等下次调度执行时,先加载进程上下文,这样CPU就知道了进程的执行情况;


结语

         以上便是本文的全部内容,希望对你有所帮助或启发,最后,感谢阅读!

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- gamedaodao.com 版权所有 湘ICP备2022005869号-6

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务