【Linux】从 fork() 到 exec():理解 Linux 进程程序替换的魔法

server/2024/10/20 18:35:08/

1.前言

进程程序替换是指一个进程用另一个新的可执行程序来替换当前正在执行的程序,这个过程通过通过exec系列函数完成。在Linux或UNIX系统中,进程程序替换通常发生在一个进程通过fork()创建了子进程之后,子进程用exec()函数加载和执行另一个程序。
也就是说,进程程序替换就是在不改变进程的PID(进程ID)的情况下,用一个全新的程序来替换当前的内存空间和执行内容。
当程序调用一种exec函数时,该进程的用户空间代码和数据完全被新的程序替换,从新程序的启动例程开始执行。

进程程序替换

2.替换函数

exec函数是一个系列函数,负责替换当前进程的映像。常见的exec函数包括:

#include <unistd.h>
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 execve(const char* path,char* const argv[],char* const envp[]);

2.1 函数解释

  • 这些函数如果调用成功则加载新的程序从启动代码开始执行,不在返回。
  • 如果调用出错则返回-1。
  • 所以exec函数只有出错的返回值而没有成功的返回值。
    使用execl测试
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
int main()
{pid_t id = fork();if(id < 0){perror("fork failed");exit(1);}if(id == 0){//childprintf("i am a child process,replacing myself with /bin/ls\n");execl("/bin/ls","ls",NULL);//使用exec替换为ls程序//如果execl执行成功,下行将不会被执行。perror("execl failed");exit(1);}else {//fatherwait(NULL);//等待子进程结束printf("child process finished\n");}return 0;
}

执行结果:

i am a child process,replacing myself with /bin/ls
a.out  pReplaceTest.c
child process finished

在这个例子中:

  • 父进程创建了一个子进程。
  • 子进程使用execl()来替换自己,将当前的进程映像替换为/bin/ls程序。
  • 替换成功后,子进程开始执行ls程序的代码,将不在执行原理的代码。
  • 父进程调用wait()等待子进程结束,执行ls命令将结果输出到控制台。
    在程序的替换函数,通常不会让父进程去执行,而是交给子进程去执行,因为父进程还需要进行完成它的时,同时也防止替换的程序造成程序崩溃。由于进程间的独立性,即使子进程去执行execl函数时候,替换的也是子进程的代码和数据,而父进程的代码和数据是不会被影响的。
    提问:发生了子进程的程序替换,此时:父进程的代码还是共享的吗?
    回答:

不是,此时发生了写时拷贝,也就是会拷贝一份代码和数据出来,然后子进程再被它的execl还是进行程序替换。

2.2 命名理解

这些函数的名称还是太相似了,为了方便记忆,可以按一下规律记忆一下。

  • l(list):表示参数采用列表。
  • v(vector):参数用数组。
  • p(path):有p自动搜索环境变量PATH。
  • e(env):表示自己维护环境变量。
函数名参数格式是否带路径是否使用当前环境变量
execl列表不是
execlp列表
execle列表不是不是,需要自己组装环境变量
execv数组不是
execvp数组
execve数组不是不是,需要自己组装环境变量

2.3 exec系列函数介绍

execl函数在上文已经介绍,这里就跳过了。

2.3.1 execlp函数

execlp函数和execl函数的区别在于,execlp在第一个参数时候,不需要全路径,只需要写上执行命令的文件名即可,表示你需要执行谁,往后也就是和execl的参数一样。

#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>int main()
{pid_t id = fork();if(id == 0){execlp("ls","ls","-a","-l",NULL);exit(1);}else if(id>0){int ret = wait(NULL);if(ret<0){perror("wait failed");}else{printf("wait success\n");}}else{perror("fork failed");exit(1);}return 0;
}

执行结果

drwxrwxr-x  2 ubuntu ubuntu  4096 Oct 20 14:18 .
drwxr-x--- 11 ubuntu ubuntu  4096 Oct 20 14:18 ..
-rwxrwxr-x  1 ubuntu ubuntu 16168 Oct 20 12:39 a.out
-rwxrwxr-x  1 ubuntu ubuntu 16168 Oct 20 14:18 execlp
-rw-rw-r--  1 ubuntu ubuntu   519 Oct 20 14:18 execlpTest.c
-rw-rw-r--  1 ubuntu ubuntu   552 Oct 20 12:39 pReplaceTest.c
-rw-rw-r--  1 ubuntu ubuntu     1 Oct 20 14:11 test.c
wait success

2.3.2 execle函数

execle函数比execl函数多一个e,按照上的设定。需要在最后一个参数需要给execle传入自定义的环境变量数组。
它的使用情况:如果你需要给你执行的一个新的程序,加载一些自定义的环境变量给新的程序时候,以可以使用该函数。
exeTest.c文件:打印环境变量的值,这个文件假如自己执行自己的话那么会打印默认的环境变量。假如其他文件使用execle传参给exeTest.c的话,exeTest.c就会执行该execle传递过来的环境变量。

#include <stdio.h>
int main()
{extern char** environ;int i = 0;for(;environ[i];i++){printf("%s\n",environ[i]);}return 0;
}

execle测试

#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>int main()
{pid_t id = fork();if(id == 0){char* const myEnv[] = {"MYVAL1 = 123","MYVAL2 = 456","MYVAL3 = 789",NULL};execle("./myexe","./myexe",NULL,myEnv);exit(1);}else if(id>0){int ret = wait(NULL);if(ret>0){printf("wait success\n");}else{perror("wait failed\n");}}else {perror("fork failed");exit(1);}return 0;
}

结果:

MYVAL1 = 123
MYVAL2 = 456
MYVAL3 = 789
wait success

2.3.3 execv函数

execv和execl函数没什么区别。execv函数把execl的以列形式的传参,变成了以数组的形式的传参。

#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>int main()
{pid_t id = fork();if(id < 0){perror("fork failed");exit(1);}if(id == 0){//childchar* const argv[]={"ls","-a","-l",NULL};execv("/bin/ls",argv);//如果execv执行成功,下行将不会被执行。perror("execl failed");exit(1);}else{//fatherwait(NULL);//等待子进程结束printf("child process finished\n");}return 0;
}

执行结果:

drwxrwxr-x  2 ubuntu ubuntu  4096 Oct 20 14:54 .
drwxr-x--- 11 ubuntu ubuntu  4096 Oct 20 14:54 ..
-rwxrwxr-x  1 ubuntu ubuntu 16216 Oct 20 14:54 a.out
-rwxrwxr-x  1 ubuntu ubuntu 16216 Oct 20 14:41 execle
-rw-rw-r--  1 ubuntu ubuntu   672 Oct 20 14:38 execleTest.c
-rwxrwxr-x  1 ubuntu ubuntu 16168 Oct 20 14:18 execlp
-rw-rw-r--  1 ubuntu ubuntu   519 Oct 20 14:18 execlpTest.c
-rw-rw-r--  1 ubuntu ubuntu   575 Oct 20 14:54 execvTest.c
-rw-rw-r--  1 ubuntu ubuntu   162 Oct 20 14:40 exeTest.c
-rwxrwxr-x  1 ubuntu ubuntu 16024 Oct 20 14:40 myexe
-rw-rw-r--  1 ubuntu ubuntu   552 Oct 20 12:39 pReplaceTest.c
-rw-rw-r--  1 ubuntu ubuntu     1 Oct 20 14:11 test.c
child process finished

如此一来,我们就讲完了:l v p e的各个结果。其他函数只需要在此基础上进行配合就是了。
exec函数

4. 总结

  • 进程程序替换是指用一个新的可执行程序替换当前进程的内存空间和执行内容,但进程ID不变。
  • 常用的替换函数是 exec 系列函数(如 execl()execvp())。
  • 它常用于父进程通过 fork() 创建子进程后,子进程用 exec() 替换为新的程序来执行指定任务。
  • 替换后的进程将完全抛弃原来的代码和数据,并开始执行新加载的程序。

如果我文章对你有所帮助的话,点个关注吧~


http://www.ppmy.cn/server/133414.html

相关文章

Kubernetes部署练习

Kubernetes详细笔记 文章目录 Kubernetes 一、Kubernetes介绍 1.1、应用部署方式演变1.2、kubernetes简介1.3、kubernetes组件1.4、kubernetes概念 二、集群环境搭建 2.1、环境规划 2.1.1、集群类型2.1.2、安装方式2.1.3、主机规划 2.2、环境搭建 2.2.1、主机安装2.2.2、环境初…

JAVA毕业设计190—基于Java+Springboot+vue的景区旅游推荐管理系统(源代码+数据库+7000字论文)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootvue的景区旅游推荐管理系统(源代码数据库7000字论文)190 一、系统介绍 本项目前后端分离&#xff0c;分为用户、商家、管理员三种角色&#xff0c;带协同过滤算…

Adobe Illustrator如何在图片快速插入latex公式

Adobe Illustrator没法直接输入latex公式&#xff0c;也没有公式的字体 解决&#xff1a; 1.装插件&#xff1a;latex2ai&#xff08;我装不上&#xff09; 2.latex公式编辑网站&#xff08;图片识别公式多了要收费&#xff09;或者其他latex公式网站&#xff0c;公式打完保…

【微信小程序_13_页面配置与网络数据请】

摘要:本文介绍了微信小程序的页面配置与网络数据请求。页面配置文件可对单个页面进行个性化设置,与全局配置冲突时以页面配置为准。网络数据请求有严格限制,包括只能用 HTTPS 接口并添加到信任列表。可通过wx.request()发起 GET 和 POST 请求,能在页面加载时自动请求数据。…

Acrel-1200——分布式光伏运维云平台

概述&#xff1a;分布式光伏发电特指在用户场地附近建设&#xff0c;运行方式以用户侧自发自用、多余电量上网&#xff0c;且在配电系统平衡调节为特征的光伏发电设施。分布式光伏发电遵循因地制宜、清洁高效、分散布局、就近利用的原则&#xff0c;充分利用当地太阳能资源&…

怎么给PPT文件设置文字动画效果,提高美观度

在制作演示文稿时&#xff0c;恰当地使用文字动画效果可以吸引观众的注意力&#xff0c;使信息传达更加生动有趣。本文将介绍一些高级技巧&#xff0c;帮助你提升PPT中文字动画的专业度和吸引力。 一、准备工作 首先&#xff0c;确保你已经打开PowerPoint并创建了一个新幻灯片…

图论day60|108.冗余连接(卡码网) 、109.冗余连接II(卡码网)【并查集 摧毁信心的一题,胆小的走开!】

图论day60|108.冗余连接&#xff08;卡码网&#xff09;、109.冗余连接II&#xff08;卡码网&#xff09;【并查集 摧毁信心的一题&#xff0c;胆小的走开&#xff01;】 108.冗余连接&#xff08;卡码网&#xff09;109.冗余连接II&#xff08;卡码网&#xff09;【并查集 摧毁…

纯血鸿蒙!

纯血鸿蒙&#xff0c;这是哪个营销大师给起的名字啊&#xff01; 纯血&#xff01;象征着高贵、自信、自主、血性、英雄气概&#xff0c;都融入这纯血鸿蒙了&#xff01; 鸿蒙本就是开天辟地&#xff0c;加上纯血&#xff0c;真是荡气回肠&#xff01; 鸿蒙的推出背景 我们前…