Linux - 进程 - 进程程序替换

一. 进程程序替换原理

fork() 创建子进程后, 子进程执行的是和父进程相同的程序 (但有可能执行不同的代码分支), 子进程往往要调用一种 exec 函数以执行另一个程序. 当进程调用一种 exec 函数时, 该进程执行的程序完全被新程序替换, 从新程序的启动例程开始执行. 调用 exec 并不创建新进程, 所以调用 exec 前后该进程的 PID 并未改变, exec 只是用磁盘上的一个新程序替换了当前进程的正文段, 数据段, 堆区和栈区.

注意: 子进程刚被创建时, 与父进程共享地址空间, 但当子进程需要进行进程程序替换时, 需要对其地址空间进行修改, 这时会发生写时复制, 此后父子进程就不再对地址空间进行共享.

二. 进程程序替换方法

替换函数有六种以 exec 开头的函数, 它们统称为 exec 函数.

execl

函数原型: int execl(const char *path, const char *arg, ...);

第一个参数是存放可执行程序的路径名, 第二个参数是可变参数列表, 传递命令行参数字符串, 并以 NULL 结尾.

例如, 要执行指令 ls -l.

execl("/usr/bin/ls", "ls", "-l", NULL);

execlp

函数原型: int execlp(const char *file, const char *arg, ...);

第一个参数是可执行程序的文件名, 第二个参数是可变参数列表, 传递命令行参数字符串, 并以 NULL 结尾.

例如, 要执行指令 ls -l.

execlp("ls", "ls", "-l", NULL);

execle

函数原型: int execle(const char *path, const char *arg, ..., char *const envp[]);

第一个参数是存放可执行程序的路径名, 第二个参数是可变参数列表, 传递命令行参数字符串, 并以 NULL 结尾, 第三个参数是一个指向环境字符串指针数组的指针. (系统默认的环境变量和自己组装的环境变量都可以)

例如, 要执行指令 ls -l, 且使用系统默认的环境变量.

execle("/usr/bin/ls", "ls", "-l", "NULL", environ);

execv

函数原型: int execv(const char *path, char *const argv[]);

第一个参数是存放可执行程序的路径名, 第二个参数是指向命令行参数字符串指针数组 (指针数组的最后一个元素必须设置为 NULL) 的指针.

例如, 要执行指令 ls -l.

c 复制代码
char* argv[] = { "ls", "-l", NULL };
execv("/usr/bin/ls", argv);

execvp

函数原型: int execvp(const char *file, char *const argv[]);

第一个参数是可执行程序的文件名, 第二个参数是指向命令行参数字符串指针数组 (指针数组的最后一个元素必须设置为 NULL) 的指针.

例如, 要执行指令 ls -l.

c 复制代码
char* argv[] = { "ls", "-l", NULL };
execvp("ls", argv);

execve

函数原型: int execve(const char *path, char *const argv[], char *const envp[]);

第一个参数是存放可执行程序的路径名, 第二个参数是指向命令行参数字符串指针数组 (指针数组的最后一个元素必须设置为 NULL) 的指针, 第三个参数是一个指向环境字符串指针数组的指针. (系统默认的环境变量和自己组装的环境变量都可以)

例如, 要执行指令 ls -l, 且使用系统默认的环境变量.

c 复制代码
char* argv[] = { "ls", "-l", NULL };
execle("/usr/bin/ls", argv, environ);

exec 函数返回值

  • exec 函数如果调用成功, 则加载指定的程序并从启动例程开始执行, 不再返回.
  • 如果调用出错, 则返回 -1.

也就是说, exec 系列函数只要返回了, 就意味着其调用失败.

命名理解

  • l(list): 表示命令行参数字符串采用列表的形式, 一一列出.
  • v(vector): 表示命令行参数字符串采用数组的形式组织.
  • p(path): 表示能通过环境变量 PATH 在它所指定的各目录中搜寻可执行文件.
  • e(env): 表示可以传入自己设置的环境变量 (也可以传入系统默认的环境变量).

事实上, 只有 execve() 才是系统调用, 其它五个函数最终都是调用的execve,所以execve在man手册的第2节,而其它五个函数在man手册的第3节,也就是说其他五个函数实际上是对系统调用execve进行了封装,以满足不同用户的不同调用场景的。

下图为 exec 系列函数之间的关系:

相关推荐
JJJennie77730 分钟前
MAI Gateway技术揭秘:大模型网关能做什么?从原理到落地
linux·服务器·网络·ai网关
风哥2号3 小时前
数据库教程FGMT02‑生产环境Linux+Oracle19c安装配置与项目实战
linux·数据库·ffmpeg
wuminyu6 小时前
Kafka中sendfile与mmap实现机制解析
java·linux·c语言·jvm·c++
新时代牛马6 小时前
嵌入式网络完整篇:从LwIP/以太网驱动到 Linux netdev 与排障
linux·网络·php
猿与禅7 小时前
Linux(Ubuntu)入门到实战:系统管理、常用命令与权限体系完整指南
linux·ubuntu·apt·进程管理·系统运维·用户权限·vi/vim
前端世界7 小时前
Linux服务器实战:NTP时间同步、SELinux权限与rsyslog日志管理,一次搞懂三大运维问题
linux·运维·服务器
Android系统攻城狮7 小时前
Linux Gstreamer深度解析之gst_audio_converter_new调用流程与实战(二十)
linux·运维·服务器·gstreamer音视频·音视频进阶
H_oRIZoN_12 小时前
Linux入门DAY41(51 单片机 串口与通信协议)
linux·运维·单片机
GeW13 小时前
RHCE备考别瞎学!按这个计划走,30天提高通过率,快速拿证
linux
Escalating_xu14 小时前
【System V 信号量】从 P/V 原语到 Builder 封装:写出可控、可清理的进程互斥组件
java·linux·开发语言·jvm