Linux操作系统2-进程控制3(进程替换,exec相关函数和系统调用)

上篇文章:Linux操作系统2-进程控制2(进程等待,waitpid系统调用,阻塞与非阻塞等待)-CSDN博客

本篇代码Gitee仓库:Linux操作系统-进程的程序替换学习 · d0f7bb4 · 橘子真甜/linux学习 - Gitee.com

本篇重点:进程替换

目录

一. 什么是进程替换?

二. 进程替换函数常用的函数 

2.1 execl 

a 进程替换覆盖指定位置后面的代码

b 进程替换不会影响父进程 

2.2 execlp 

 2.3 execv/execvp

2.4 execle 

 2.5 execve 系统调用

 三. 进程替换总结

四. 进程替换可以执行任何后端语言!


一. 什么是进程替换?

        我们知道,使用fork函数可以创建子进程。我们创建子进程的目的是什么?

1 让子进程执行父进程的一部分代码(比如执行父进程处于磁盘中的代码)

2 我们希望让子进程执行一个全新的进程,去完成一个不同的功能

        我们让子进程去执行新程序的数据和代码 -> 进程的程序替换

二. 进程替换函数常用的函数 

常见的函数如下:

#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 execl 

a 进程替换覆盖指定位置后面的代码

int execl(const char *path, const char *arg, ...);    //path    用于找到程序(程序的路径,ls的路径是 /usr/bin/ls)
//arg     这个命令是怎么执行的(比如ls命令的执行方式就是单独的 ls)
//...     这个命令需要的参数是什么(比如ls可以带参数 -a -l -i 等)//返回值,失败返回-1,并且设置错误码

我们使用execl去替换一个 ls命令。代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main()
{// 使用execl去替换ls完成  ls -a -l --color=autoprintf("process is running!\n");//第一个参数,要执行哪个路径,就填这个路径//第二个参数,程序怎么执行,就怎么填//后面的参数,执行这个程序需要带的参数,就一个一个地填这些参数//最好使用NULL结尾int n = execl("/usr/bin/ls", "ls", "-a", "-l", "--color=auto", NULL);//使用系统调用或者涉及底层的C库函数,需要判断错误返回perror("execl");//由于执行execl之后,代码被覆盖,以下的代码不会被运行!printf("process is running!\n");printf("process is running!\n");printf("process is running!\n");printf("process is running!\n");printf("process is running!\n");return 0;
}

编译运行结果如下:

        execl之后的代码没有被执行的原因是:进程替换的时候没有创建新进程,而是将指定的程序和代码加载到指定的位置

        这样会覆盖后面的代码,所以后面printf就不会执行了!

b 进程替换不会影响父进程 

        进程替换会覆盖指定位置后面的代码,不过我们在子进程中使用进程替换不会影响父进程的代码和数据。

       这个原因是父子进程之间有写实拷贝,由于父子进程之间的写实拷贝,一旦子进程尝试写入,OS就会给子进程开辟一份空间用于保存子进程的数据和代码。这样一来,子进程进程替换就不会影响父进程。

测试代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>int main()
{// 使用execl去替换ls完成  ls -a -l --color=autoprintf("1 process is running!\n");pid_t id = fork();if (id == 0){int n = execl("/usr/bin/ls", "ls", "-a", "-l", "--color=auto", NULL);perror("execl");// 如果替换失败exit(-1);}// 由于写实拷贝,父进程不受子进程进程替换影响printf("2 process is running!\n");int status = 0;int subid = waitpid(id, &status, 0);if (subid > 0){printf("child exit code:%d child exit signal\n", (status >> 8) & 0xff, status & 0x7f);}return 0;
}

测试结果: 

 

2.2 execlp 

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

p:path,只要输入替换的程序,会自动去环境变量中进行查找。无需告诉路径

测试代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>int main()
{// 使用execl去替换ls完成  ls -a -l --color=autoprintf("1 process is running!\n");pid_t id = fork();if (id == 0){//p:path,只要输入替换的程序,会自动去环境变量中进行查找。无需告诉路径execlp("ls", "ls", "-a", "-l", "--color=auto", NULL);perror("execl");// 如果替换失败exit(-1);}// 由于写实拷贝,父进程不受子进程进程替换影响printf("2 process is running!\n");int status = 0;int subid = waitpid(id, &status, 0);if (subid > 0){printf("child exit code:%d child exit signal\n", (status >> 8) & 0xff, status & 0x7f);}return 0;
}

测试结果:

 2.3 execv/execvp

//v:vector:可以将所有的执行参数放入数组,进行统一传入,不用可变参数传参 
int execv(const char *path, char *const argv[]);    // v:vector p:文件名
int execvp(const char *file, char *const argv[]);  

execv 举例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>int main()
{// 使用execl去替换ls完成  ls -a -l --color=autoprintf("1 process is running!\n");pid_t id = fork();if (id == 0){char * argv_[] = {"ls", "-a", "-l", "--color=auto", NULL}; execv("/usr/bin/ls", argv_);perror("execv");// 如果替换失败exit(-1);}// 由于写实拷贝,父进程不受子进程进程替换影响printf("2 process is running!\n");int status = 0;int subid = waitpid(id, &status, 0);if (subid > 0){printf("child exit code:%d child exit signal\n", (status >> 8) & 0xff, status & 0x7f);}return 0;
}

测试结果:

 

 execvp 加上了p:我们只需给出名字,会去环境变量中自动查找

测试代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>int main()
{// 使用execl去替换ls完成  ls -a -l --color=autoprintf("1 process is running!\n");pid_t id = fork();if (id == 0){char * argv_[] = {"ls", "-a", "-l", "--color=auto", NULL}; execvp("ls", argv_);perror("execvp");// 如果替换失败exit(-1);}// 由于写实拷贝,父进程不受子进程进程替换影响printf("2 process is running!\n");int status = 0;int subid = waitpid(id, &status, 0);if (subid > 0){printf("child exit code:%d child exit signal\n", (status >> 8) & 0xff, status & 0x7f);}return 0;
}

测试结果:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>int main()
{// 使用execl去替换ls完成  ls -a -l --color=autoprintf("1 process is running!\n");pid_t id = fork();if (id == 0){char * argv_[] = {"ls", "-a", "-l", "--color=auto", NULL}; execvp("ls", argv_);perror("execvp");// 如果替换失败exit(-1);}// 由于写实拷贝,父进程不受子进程进程替换影响printf("2 process is running!\n");int status = 0;int subid = waitpid(id, &status, 0);if (subid > 0){printf("child exit code:%d child exit signal\n", (status >> 8) & 0xff, status & 0x7f);}return 0;
}

测试结果

2.4 execle 

int execle(const char *path, const char *arg, ...,char *const envp[]);    //e:传入自定义环境变量,

e:传入自定义环境变量

我们定义另一个C程序mybin,让这个程序打印环境变量。然后我们在子进程中替换为mybin

这样我们的子进程就能够打印我们在execle函数中输入的环境变量了

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>int main()
{// 使用execl去替换ls完成  ls -a -l --color=autoprintf("1 process is running!\n");pid_t id = fork();if (id == 0){//注意在最后加上NULLchar *const env_[] = {"AA=11", "BB=22", "CC=33", "YZC=Hello world!", NULL};// 加入命令行参数envexecle("./mybin", "./mybin", NULL, env_);perror("execle");// 如果替换失败exit(-1);}// 由于写实拷贝,父进程不受子进程进程替换影响printf("2 process is running!\n");int status = 0;int subid = waitpid(id, &status, 0);if (subid > 0){printf("child exit code:%d child exit signal\n", (status >> 8) & 0xff, status & 0x7f);}return 0;
}

运行结果如下:

 我们换成系统环境变量

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>int main()
{// 使用execl去替换ls完成  ls -a -l --color=autoprintf("1 process is running!\n");pid_t id = fork();if (id == 0){//注意在最后加上NULLchar *const env_[] = {"AA=11", "BB=22", "CC=33", "YZC=Hello world!", NULL};// 加入命令行参数envextern char** environ;execle("./mybin", "./mybin", NULL, environ);perror("execle");// 如果替换失败exit(-1);}// 由于写实拷贝,父进程不受子进程进程替换影响printf("2 process is running!\n");int status = 0;int subid = waitpid(id, &status, 0);if (subid > 0){printf("child exit code:%d child exit signal\n", (status >> 8) & 0xff, status & 0x7f);}return 0;
}

运行结果: 

当然我们也能够在 命令行参数获取环境变量

 2.5 execve 系统调用

上面的exec函数都是对execve系统调用的封装

//2号手册,这个才是真正的系统调用(上面的都是函数封装)
int execve(const char *path, char *const argv[], char *const envp[]);

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>int main()
{// 使用execl去替换ls完成  ls -a -l --color=autoprintf("1 process is running!\n");pid_t id = fork();if (id == 0){// 注意在最后加上NULLchar *const env_[] = {"AA=11", "BB=22", "CC=33", "YZC=Hello world!", NULL};char *const argv_[] = {"./mybin"};execve("./mybin", argv_, env_);perror("execve");// 如果替换失败exit(-1);}// 由于写实拷贝,父进程不受子进程进程替换影响printf("2 process is running!\n");int status = 0;int subid = waitpid(id, &status, 0);if (subid > 0){printf("child exit code:%d child exit signal\n", (status >> 8) & 0xff, status & 0x7f);}return 0;
}

测试结果: 

 三. 进程替换总结

我们知道程序必须加载到内存中才能执行。这是由冯诺依曼计算机体系结构决定的。

在Linux中就是通过exec*函数来加载程序的!

那么是exec函数先加载还是main函数先执行?

exec函数先加载,然后main函数再执行

我们可以发现exec函数的参数和main函数的参数很像!

所以是exec函数先加载路径,参数,环境变量在执行main函数 

四. 进程替换可以执行任何后端语言!

myCppBin.cc

#include <iostream>
using namespace std;int main()
{cout << "Hello C++!" << endl;return 0;
}

mytest.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>int main()
{// 使用execl去替换ls完成  ls -a -l --color=autoprintf("1 process is running!\n");pid_t id = fork();if (id == 0){// 注意在最后加上NULLchar *const env_[] = {"AA=11", "BB=22", "CC=33", "YZC=Hello world!", NULL};char *const argv_[] = {"./myCppBin"};//执行C程序//execve("./mybin", argv_, env_);//执行C++execve("./myCppBin", argv_, env_);perror("execve");// 如果替换失败exit(-1);}// 由于写实拷贝,父进程不受子进程进程替换影响printf("2 process is running!\n");int status = 0;int subid = waitpid(id, &status, 0);if (subid > 0){printf("child exit code:%d child exit signal\n", (status >> 8) & 0xff, status & 0x7f);}return 0;
}

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

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

相关文章

0基础学前端系列 -- 深入理解 HTML 布局

在现代网页设计中&#xff0c;布局是至关重要的一环。良好的布局不仅能提升用户体验&#xff0c;还能使内容更具可读性和美观性。HTML&#xff08;超文本标记语言&#xff09;结合 CSS&#xff08;层叠样式表&#xff09;为我们提供了多种布局方式。本文将详细介绍流式布局、Fl…

Springboot集成通义大模型

1.先到阿里云平台开头阿里云白炼账号&#xff0c;创建apiKey 2. 引入maven依赖 <dependency><groupId>com.alibaba</groupId><artifactId>dashscope-sdk-java</artifactId><version>2.8.3</version></dependency><!-- htt…

哈希表算法题

目录 题目一——1. 两数之和 - 力扣&#xff08;LeetCode&#xff09; 1.1.暴力解法1 1.2.暴力解法2 1.2.哈希表解法 题目二——面试题 01.02. 判定是否互为字符重排 - 力扣&#xff08;LeetCode&#xff09; 2.1.哈希表解法 2.2.排序解法 题目三——217. 存在重复元…

Cookie跨域

跨域&#xff1a;跨域名&#xff08;IP&#xff09; 跨域的目的是共享Cookie。 session操作http协议&#xff0c;每次既要request&#xff0c;也要response&#xff0c;cookie在创建的时候会产生一个字符串然后随着response返回。 全网站的各个页面都会带着登陆的时候的cookie …

个人博客接入github issue风格的评论,utteranc,gitment

在做个人博客的时候&#xff0c;如果你需要评论功能&#xff0c;但是又不想构建用户体系和评论模块&#xff0c;那么可以直接使用github的issue提供的接口&#xff0c;对应的开源项目有utteranc和gitment&#xff0c;尤其是前者。 它们的原理是一样的&#xff1a;在博客文章下…

React第十节组件之间传值之context

1、Context 使用creatContext() 和 useContext() Hook 实现多层级传值 概述&#xff1a; 在我们想要每个层级都需要某一属性&#xff0c;或者祖孙之间需要传值时&#xff0c;我们可以使用 props 一层一层的向下传递&#xff0c;或者我们使用更便捷的方案&#xff0c;用 creatC…

JVM_垃圾收集器详解

1、 前言 JVM就是Java虚拟机&#xff0c;说白了就是为了屏蔽底层操作系统的不一致而设计出来的一个虚拟机&#xff0c;让用户更加专注上层&#xff0c;而不用在乎下层的一个产品。这就是JVM的跨平台&#xff0c;一次编译&#xff0c;到处运行。 而JVM中的核心功能其实就是自动…

RPA:电商订单处理自动化

哈喽&#xff0c;大家好&#xff0c;我是若木&#xff0c;最近闲暇时间较多&#xff0c;于是便跟着教程做了一个及RPA&#xff0c;谈到这个&#xff0c;可能很多人并不是很了解&#xff0c;但是实际上&#xff0c;这玩意却遍布文末生活的边边角角。话不多说&#xff0c;我直接上…

字符型注入‘)闭合

前言 进行sql注入的时候&#xff0c;不要忘记闭合&#xff0c;先闭合再去获取数据 步骤 判断是字符型注入 用order by获取不了显位&#xff0c;select也一样 是因为它是’)闭合&#xff0c;闭合之后&#xff0c;就可以获取数据了 最后就是一样的步骤

springboot车辆管理系统设计与实现(代码+数据库+LW)

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了车辆管理系统的开发全过程。通过分析车辆管理系统管理的不足&#xff0c;创建了一个计算机管理车辆管理系统的方案。文章介绍了车辆管理系统的系统分析部分&…

C#.Net筑基 - 常见类型

01、结构体类型Struct 结构体 struct 是一种用户自定义的值类型&#xff0c;常用于定义一些简单&#xff08;轻量&#xff09;的数据结构。对于一些局部使用的数据结构&#xff0c;优先使用结构体&#xff0c;效率要高很多。 可以有构造函数&#xff0c;也可以没有。因此初始化…

Unity项目性能优化列表

1、对象池 2、检查内存是否泄露。内存持续上升(闭包、委托造成泄露) 3、检查DrawCall数量&#xff0c;尽量减少SetPassCall 4、尽量多的利用四种合批 动态合批(Dynamic Batching)静态合批(Static Batching)GPUInstancingSRP Batcher 动态合批消耗内存把多个网格组合在一起合并…

ComfyUI | ComfyUI桌面版发布,支持winmac多平台体验,汉化共享等技巧!(内附安装包)

ComfyUI 桌面版正式推出&#xff0c;支持 Windows 与 macOS 等多平台&#xff0c;为 AI 绘画爱好者带来全新体验。其安装包便捷易用&#xff0c;开启了轻松上手之旅。汉化共享功能更是一大亮点&#xff0c;打破语言障碍&#xff0c;促进知识交流与传播。在操作上&#xff0c;它…

贪心-区间问题——acwing

题目一&#xff1a;最大不相交区间数量 908. 最大不相交区间数量 - AcWing题库 分析 跟区间选点一样。区间选点&#xff1a;贪心——acwing-CSDN博客 代码 #include<bits/stdc.h> using namespace std;const int N 1e510;struct Range {int l, r;// 重载函数bool op…

【C语言】字符串左旋的三种解题方法详细分析

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C语言 文章目录 &#x1f4af;前言&#x1f4af;题目描述&#x1f4af;方法一&#xff1a;逐字符移动法&#x1f4af;方法二&#xff1a;使用辅助空间法&#x1f4af;方法三&#xff1a;三次反转法&#x1f4af;方法对…

肿瘤微环境中单细胞的泛癌分类

scRNA-seq可以揭示肿瘤微环境 (TME) 内细胞异质性的宝贵见解&#xff0c;scATOMIC是一种用于恶性和非恶性细胞的注释工具。在 300,000 个癌症、免疫和基质细胞上训练了 scATOMIC&#xff0c;为 19 种常见癌症定义了一个泛癌症参考&#xff0c;scATOMIC优于当前的分类方法。在 2…

《算法导论》英文版前言To the teacher第3段研习录:题海战术有没有?

【英文版】 We have included 957 exercises and 158 problems. Each section ends with exercises, and each chapter ends with problems. The exercises are generally short questions that test basic mastery of the material. Some are simple self-check thought exer…

docker使用(镜像、容器)

docker基础使用 文章目录 前言1.镜像操作1.1命令介绍1.2.案例实操1.2.1查找镜像1.2.2下载镜像1.2.3查看当前镜像 2.容器操作2.1命令2.1.1容器创建与启动2.1.2. 容器查看2.1.3. 容器操作2.1.4. 容器删除2.1.5. 容器日志2.1.6. 容器内文件操作2.1.7. 容器内命令执行2.1.8. 其他常…

自编码器(二)

自编码器到底好在哪里&#xff1f;当我们把一个高维度的图片&#xff0c;变成一个低维度的向量的时候&#xff0c;到 底带来什么样的帮助呢&#xff1f;我们来设想一下&#xff0c;自编码器这件事情它要做的&#xff0c;是把一张图片压缩 又还原回来&#xff0c;但是还原这件事…

springboot旅游管理系统的设计与实现

springboot旅游管理系统的设计与实现 如需源码pc端&#x1f449;&#x1f449;&#x1f449;资源 手机端&#x1f449;&#x1f449;&#x1f449;资源 摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于…