Linux系统:进程程序替换以及相关exec接口

本节重点

  • 理解进程替换的相关概念与原理
  • 掌握相关程序替换接口
  • 程序替换与进程创建的区别
  • 程序替换的注意事项

一、概念与原理

进程程序替换是操作系统中实现多任务和资源复用的关键机制,允许进程在运行时动态加载并执行新程序。

1.1 定义

进程程序替换是指用新程序的代码、数据和堆栈完全替换当前进程的地址空间(加载新程序到内存、更新页表映射、初始化虚拟地址空间,并将进程控制块(PCB)指向新程序),使进程执行新程序的逻辑,而进程ID(PID)保持不变

1.2 与进程创建的区别

  • 进程创建(fork):创建新进程,并分配PID
  • 进程程序替换:不创建新进程,更改原程序的代码与数据

二、实现方法 exec函数(6+1)

2.1 语言封装(6)

2.1.1 execl

函数原型:

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

参数:

pathname:新程序的路径+文件名

arg:传递给新程序的参数

代码示例:

#include<iostream>
#include<cstdio>
#include<unistd.h>
int main()
{printf("进程替换之前!\n");int ret=execl("/bin/ls","ls","-a","-l",NULL);//进程替换成功后后续代码不会执行//只有进程替换出错后才会执行后续代码,并设置错误码(void)ret;printf("进程替换之后!\n");return 0;
}

运行结果:

2.1.2 execlp

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

 参数解析:

file:新程序的程序名

arg:传递给新程序的参数/执行的方法

代码示例:

#include<iostream>
#include<cstdio>
#include<unistd.h>int main()
{printf("进程替换之前!:\n");int ret=execlp("ls","ls","-a","-l",NULL);(void)ret;if(ret==-1)printf("execlp fail!\n");printf("进程替换之后!:\n");return 0;
}

运行结果:

2.1.3 execle

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

 参数解析: 

pathname:新程序的路径+文件名

arg:传递给新程序的参数/执行新程序的方法

envp:传递给新程序的环境变量表(以NULL结尾)

代码示例:

code.cc

#include<iostream>
#include<cstdio>
#include<unistd.h>int main()
{printf("进程替换之前!:\n");char* const env[]={(char* const)"other=12345",(char* const)"n1=45612",(char* const)"n2=56784",(char* const)"n3=12034",(char* const)"n4=yuejianhua",(char* const)"n5=jinzhiqi",NULL,};int ret=execle("./text","text",NULL,env);if(ret==-1)printf("execlp fail!\n");printf("进程替换之后!:\n");return 0;
}

text.cc 

#include<iostream>
#include<cstdio>
#include<unistd.h>int main(int argc,char* argv[],const char* env[])
{//打印环境变量表:int i=0;while(env[i]){std::cout<<env[i]<<std::endl;i++;}i=0;//打印命令行参数列表:while(argv[i]){std::cout<<argv[i]<<std::endl;i++;} return 0;
}

运行结果:

2.1.4 execv

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

 参数解析: 

pathname:新程序的路径+文件名

argv:传递给新程序的命令行参数列表(以NULL结尾)

代码示例:

#include<iostream>
#include<cstdio>
#include<unistd.h>int main()
{printf("进程替换之前!:\n");char* const argv[]={(char* const)"ls",(char* const)"-a",(char* const)"-l",NULL,};int ret=execv("/bin/ls",argv);if(ret==-1)printf("execlp fail!\n");printf("进程替换之后!:\n");return 0;
}

运行结果:

2.1.5 execvp

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

 参数解析: 

file:新程序的文件名

argv:传递给新程序的命令行参数表(以NULL结尾)

代码示例:

code.cc

#include<iostream>
#include<cstdio>
#include<unistd.h>int main()
{printf("进程替换之前!:\n");char* const argv[]={(char* const)"yuejianhua",(char* const)"jinzhiqi",NULL,};int ret=execvp("./text",argv);if(ret==-1)printf("execlp fail!\n");printf("进程替换之后!:\n");return 0;
}

text.cc

#include<iostream>
#include<cstdio>
#include<unistd.h>int main(int argc,char* argv[],char* env[])
{//打印环境变量表:int i=0;//打印命令行参数列表:while(argv[i]){std::cout<<argv[i]<<std::endl;i++;}  return 0;
}

 运行结果:

2.1.6 execvpe

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

 参数解析: 

file:新程序的函数名

argv:传递给新程序的命令行参数列表(以NULL结尾)

envp:传递给新程序的环境变量表(以NULL结尾)

code.cc

#include<iostream>
#include<cstdio>
#include<unistd.h>int main()
{printf("进程替换之前!:\n");char* const argv[]={(char* const)"yuejianhua",(char* const)"jinzhiqi",NULL,};char* const env[]={(char* const)"other=12345",(char* const)"n1=45612",(char* const)"n2=56784",(char* const)"n3=12034",NULL,};int ret=execvpe("./text",argv,env);if(ret==-1)printf("execlp fail!\n");printf("进程替换之后!:\n");return 0;
}

text.cc

#include<iostream>
#include<cstdio>
#include<unistd.h>int main(int argc,char* argv[],char* env[])
{//打印环境变量表:int i=0;while(env[i]){std::cout<<env[i]<<std::endl;i++;} i=0;//打印命令行参数列表:while(argv[i]){std::cout<<argv[i]<<std::endl;i++;}  return 0;
}

运行结果:

2.2 系统调用(1)

2.2.1 execve

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

参数解析: 

pathname:新程序的路径+文件名

argv:传递给新程序的命令行参数表(以NULL结尾)

envp:传递给新程序的环境变量表(以NULL结尾)

代码示例:

code.cc

#include<cstdio>
#include<iostream>
#include<unistd.h>
int main()
{std::cout<<"这是进程替换之前"<<std::endl;//传递自己的命令行参数与环境变量表char* const argv[]={(char* const)"yuejianhua",(char* const)"jinzhiqi",NULL,};char* const env[]={(char* const)"n1=12345",(char* const)"n2=45678",(char* const)"n3=lut",NULL,};int ret=execve("./text",argv,env);//替换成功后续代码不会执行if(ret<0){std::cout<<"进程替换失败!"<<std::endl;}std::cout<<"进程替换之后"<<std::endl;return 0;
}

text.cc

#include<cstdio>
#include<iostream>int main(int argc,char* argv[],char* env[])
{int i=0;while(argv[i]){std::cout<<argv[i]<<std::endl;i++;}i=0;while(env[i]){std::cout<<env[i]<<std::endl;i++;}return 0;
}

 运行结果:

2.3 总结 

函数参数传递方式环境变量路径搜索示例调用
execl  可变参数列             表     继承 需完整路             径execl("/bin/ls", "ls", "-l", NULL)
execlp可变参数列表继承支持 PATHexeclp("ls", "ls", "-l", NULL)
execle可变参数列表显式传递需完整路径execle("/bin/ls", "ls", "-l", NULL, envp)
execv参数数组继承需完整路径char *argv[] = {"ls", "-l", NULL}; execv("/bin/ls", argv);
execvp参数数组继承支持 PATHexecvp("ls", argv);
execve参数数组显式传递需完整路径execve("/bin/ls", argv, envp);

 知识点:

进程程序替换所关联的exec族函数都有一个显著特征就是exec+参数传递的方式,每个字母代表特定的传参方法,以下是关于这一类型的总结:

  • l (list)      :表示给新进程传参需要一个个传
  • p(PATH):表示索引新进程可以只传递文件名,但是要是自己的代码文件必须指明路径
  • v(vector):表示给新进程传参可以直接使用自定义命令行参数列表
  • e(env)    :表示可以给新进程传递自定义环境变量表

这里需要注意的是命令行参数列表与环境变量表必须都以NULL结尾。 

exec族函数在底层都封装了系统调用execve。

当在进程替换的时候显式地给新进程传递环境变量表时传递的环境变量表会覆盖默认的环境变量表,可以参考execle的代码演示。

三、进程替换的用途

在后期我们可以通过fork+exec机制创建子进程利用进程替换机制使子进程执行定义好的代码文件。

如:Shell执行命令(简易版):

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>int main() {pid_t pid = fork();if (pid == 0) {// 子进程:替换为 ls 命令char *argv[] = {"ls", "-l", NULL};execvp("ls", argv); // 自动搜索 PATHperror("execvp failed");exit(1);} else if (pid > 0) {// 父进程:等待子进程结束wait(NULL);printf("Command executed.\n");} else {perror("fork failed");}return 0;
}

fork+exec机制使用后要注意资源回收的问题,使用进程等待的方式回收或使用信signal(SIGCHLD, SIG_IGN) 自动回收(需谨慎)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/903940.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从此,K8S入门0门槛!

前言 当你想要入门K8S的时候&#xff0c;往往会被各种概念搞的晕乎乎的&#xff0c;什么API Server&#xff0c;Scheduler&#xff0c;Controller manager&#xff0c;Etcd&#xff0c;Pod&#xff0c;Kubelet&#xff0c;kube-proxy&#xff0c;deployment…… 哪怕你使用了…

[Python开发] 如何用 VSCode 编写和管理 Python 项目(从 PyCharm 转向)

在 Python 开发领域,PyCharm 一直是广受欢迎的 IDE,但其远程开发功能(如远程 SSH 调试)仅在付费版中提供。为了适应服务器部署需求,很多开发者开始将目光转向更加轻量、灵活且免费扩展能力强的 VSCode。本篇文章将详细介绍,从 PyCharm 转向 VSCode 后,如何高效搭建和管理…

处方流转平台权限控制模块设计(基于RBAC模型)

这是基于笔者的一些经验设计并加以完善的方案&#xff0c;仅供参考。 处方流转平台权限控制模块设计&#xff08;基于RBAC模型&#xff09; 1. 需求分析 处方流转平台需要严格的权限控制&#xff0c;确保&#xff1a; 患者隐私数据保护处方开具、审核、调配、发药等流程的合…

基于BM1684X+RK3588的智能工业视觉边缘计算盒子解决方案

智能工业视觉边缘计算终端技术方案书‌ ‌1. 产品概述‌ 1.1 产品定位 面向工业自动化场景的高性能AI视觉处理设备集成BM1684X&#xff08;8TOPS INT8&#xff09;AI加速芯片 RK3588&#xff08;6TOPS NPU&#xff09;异构计算支持工业级多相机接入、实时缺陷检测、高精度定…

软件工程中的 QFD

: 软件工程中的 QFD 在软件工程领域,随着市场竞争的加剧和用户需求的日益复杂,如何有效地将用户需求转化为软件产品,成为软件开发团队面临的重要挑战。而质量功能部署(Quality Function Deployment,QFD)作为一种强大的工具,为这一问题提供了有效的解决方案。 一、QF…

Vue2基础速成

一、准备工作 首先下载vue2的JavaScript库&#xff0c;并且命名为vue.min.js 下载链接&#xff1a;https://cdn.jsdelivr.net/npm/vue2&#xff08;若链接失效可去vue官网寻找&#xff09; CTRLS即可下载保存 文件目录结构 二、使用操作原生DOM与使用VUE操作DOM的便捷性比较…

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(14):かもしれません (~た・~ない)ほうがいいです

日语学习-日语知识点小记-构建基础-JLPT-N4阶段&#xff08;1&#xff14;&#xff09;&#xff1a;かもしれません &&#xff08;&#xff5e;た・&#xff5e;ない&#xff09;ほうがいいです 1、前言&#xff08;1&#xff09;情况说明&#xff08;2&#xff09;工程师…

传统银行服务和 区块链支付无缝融合的一种解决方案

Dragonfly Capital 的合伙人 Alex Pack 曾表示:“DeFi 的目标是重构全球银行体系,并打造开放且无须许可的经营环境。”在 DeFi 的金融世界中,加密资产架构在区块链上,通过各个协议实现资产之间的高效转移和价值的实时流通,如 Metamask 钱包的自托管,Uniswap 的资产交易,…

基于深度学习的毒蘑菇检测

文章目录 任务介绍数据概览数据处理数据读取与拼接字符数据转化标签数据映射数据集划分数据标准化 模型构建与训练模型构建数据批处理模型训练 文件提交结果附录 任务介绍 本次任务为毒蘑菇的二元分类&#xff0c;任务本身并不复杂&#xff0c;适合初学者&#xff0c;主要亮点…

时间给了我们什么?

时间给了我们什么&#xff1f; ​春秋易逝&#xff0c;青春难留&#xff0c;转瞬之间已过半百。 ​过往中&#xff0c;有得有失&#xff0c;这就是人生。 ​一日三餐四季&#xff0c;日起日落里&#xff0c;成就了昨天、今天和明天&#xff0c;在历史长河中&#xff0c;皆是…

软件工程国考

软件工程-同等学力计算机综合真题及答案 &#xff08;2004-2014、2017-2024&#xff09; 2004 年软工 第三部分 软件工程 &#xff08;共 30 分&#xff09; 一、单项选择题&#xff08;每小题 1 分&#xff0c;共 5 分&#xff09; 软件可用性是指&#xff08; &#xff09…

数据结构*栈

栈 什么是栈 这里的栈与我们之前常说的栈是不同的。之前我们说的栈是内存栈&#xff0c;它是JVM内存的一部分&#xff0c;用于存储局部变量、方法调用信息等。每个线程都有自己独立的栈空间&#xff0c;当线程启动时&#xff0c;栈就会被创建&#xff1b;线程结束&#xff0c…

IntelliJ IDEA 保姆级使用教程

文章目录 一、创建项目二、创建模块三、创建包四、创建类五、编写代码六、运行代码注意 七、IDEA 常见设置1、主题2、字体3、背景色 八、IDEA 常用快捷键九、IDEA 常见操作9.1、类操作9.1.1、删除类文件9.1.2、修改类名称注意 9.2、模块操作9.2.1、修改模块名快速查看 9.2.2、导…

HTTP 快速解析

一、HTTP请求结构 HTTP请求和响应报文由以下部分组成&#xff08;以请求报文为例&#xff09;&#xff1a; 请求报文结构&#xff1a; 请求行&#xff1a;包含HTTP方法&#xff08;如GET/POST&#xff09;、请求URL和协议版本&#xff08;如HTTP/1.1&#xff0c;HTTP/2.0&…

【AI学习】李宏毅新课《DeepSeek-R1 这类大语言模型是如何进行「深度思考」(Reasoning)的?》的部分纪要

针对推理模型&#xff0c;主要讲了四种方法&#xff0c;两种不需要训练模型&#xff0c;两种需要。 对于reason和inference&#xff0c;这两个词有不同的含义&#xff01; 推理时计算不是新鲜事&#xff0c;AlphaGo就是如此。 这张图片说明了将训练和推理时计算综合考虑的关系&…

Kotlin Flow流

一 Kotlin Flow 中的 stateIn 和 shareIn 一、简单比喻理解 想象一个水龙头&#xff08;数据源&#xff09;和几个水杯&#xff08;数据接收者&#xff09;&#xff1a; 普通 Flow&#xff08;冷流&#xff09;&#xff1a;每个水杯来接水时&#xff0c;都要重新打开水龙头从…

【嵌入式Linux】基于ARM-Linux的zero2平台的智慧楼宇管理系统项目

目录 1. 需求及项目准备&#xff08;此项目对于虚拟机和香橙派的配置基于上一个垃圾分类项目&#xff0c;如初次开发&#xff0c;两个平台的环境变量&#xff0c;阿里云接入&#xff0c;摄像头配置可参考垃圾分类项目&#xff09;1.1 系统框图1.2 硬件接线1.3 语音模块配置1.4 …

Linux运维中常用的磁盘监控方式

在Linux运维中&#xff0c;磁盘监控是一项关键任务&#xff0c;因为它能帮助我们预防磁盘空间不足或性能问题导致的服务中断或数据丢失。让我们来看看有哪些常用的磁盘监控方法吧&#xff01; 1. 查看磁盘使用情况&#xff08;df命令&#xff09; df命令用于显示文件系统的…

OpenCV第6课 图像处理之几何变换(缩放)

1.简述 图像几何变换又称为图像空间变换,它将一幅图像中的坐标位置映射到另一幅图像中的新坐标位置。几何变换并不改变图像的像素值,只是在图像平面上进行像素的重新安排。 根据OpenCV函数的不同,本节课将映射关系划分为缩放、翻转、仿射变换、透视等。 2.缩放 2.1 函数…

(35)VTK C++开发示例 ---将图片映射到平面2

文章目录 1. 概述2. CMake链接VTK3. main.cpp文件4. 演示效果 更多精彩内容&#x1f449;内容导航 &#x1f448;&#x1f449;VTK开发 &#x1f448; 1. 概述 与上一个示例不同的是&#xff0c;使用vtkImageReader2Factory根据文件扩展名或内容自动创建对应的图像文件读取器&a…