【Linux】进程替换(七)

devtools/2025/3/4 6:01:18/

目录

前言:

一、进程替换

二、execl函数

1.进程替换函数的返回值

2.多进程进行程序替换

三、execv函数

四、execlp函数

五、execvpe函数

六、新增环境变量

七、系统调用的函数

总结:


前言:

我们知道了进程退出信息,进程的一些属性,进程调度算法等等,这些知识其实都是在为你学习本章内容做铺垫,如果一个子进程不想执行任何关于父进程的内容怎么办呢?本章我们学习进程替换,也是一个非常重磅的内容,我们开始吧!

一、进程替换

我们之前写的子进程都会读取父进程的代码,如果我们不想读取父进程代码,直接执行新的程序呢?就需要用到程序替换系统调用接口了。

一共7个关于进程替换的接口,我们要具体掌握其中5个。

其中最后的参数...大家是否还有印象?对,它就是可变参数列表,我们使用的printf函数中源代码就有他。

二、execl函数

我们先来使用第一个execl函数,来观察它的具体使用方法:

#include<iostream>
#include<cstdio>
#include<unistd.h>int main()
{execl("/bin/ls", "ls", "-l", "-a", nullptr); //最后必须以nullptr结尾return 0;
}

可以发现,我们可以让代码执行系统的命令,也就是程序替换。

所以进程替换是创建新进程吗?并不是,只是把代码和数据替换,修改了页表映射,但PCB信息并不变。

我们来具体讲解一下execl函数:

我们也可以验证到底有没有产生新进程,我们再编写一个other的.c文件,并把它的pid打印出来:

所以进程替换和创建子进程不一样! 

1.进程替换函数的返回值

execl这类进程替换函数它要有返回值吗?我们再来通过代码验证:

我们还是以ls这个进程替换作为对象,我们执行一个ls的正确命令和执行一个不存在的lsssss命令

所以execl这样的函数返回了就是失败了! 有很多函数的返回值我们都不需要关心,比如exit。

2.多进程进行程序替换

刚才是使用单进程进行程序替换,接下来我们使用多进程进行程序替换。创建子进程之后让子进程进行程序替换。

#include<iostream>
#include<cstdio>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>int main()
{pid_t id = fork();if (id == 0){//子进程sleep(3);execl("/bin/ls", "ls", "-l", "--color", "-a", nullptr);exit(1);}//父进程pid_t rid = waitpid(id, nullptr, 0);if (rid > 0){printf("等待子进程成功!\n");}return 0;
}

其实系统最开始会创建一个进程(bash),之后我们输入命令其实本质就是fork之后进程替换execl,所以我们可以实现一个简单的shell。 

三、execv函数

不多废话,上代码!

int main()
{pid_t id = fork();if (id == 0){//子进程char *const argv[] = {"ls", "--color", "-a", "-l", nullptr};execv("/usr/bin/ls", argv);exit(1);}//父进程pid_t rid = waitpid(id, nullptr, 0);if (rid > 0){printf("等待子进程成功!\n");}return 0;
}

命令行参数是如何传给你的程序的?我们在执行程序的时候,命令行帮我们fork并且execv了。是命令行将我们输入的字符串组织成数组,通过execv将参数传入。

其实execl内部把这些参数形成表,之后传入调用的命令main函数中,也顺便统计了个数。

四、execlp函数

这里再补充一下:

l: list
v: vector

结果都是一样的。 

五、execvpe函数

我们在写一个新程序让其打印环境变量。

之后修改myexec.cc的代码,让other程序作为替换的进程:

int main()
{pid_t id = fork();if (id == 0){//子进程char* const env[] = {(char*)"HELLO=bite"};execvpe("./other", nullptr, env);exit(1);}//父进程pid_t rid = waitpid(id, nullptr, 0);if (rid > 0){printf("等待子进程成功!\n");}return 0;
}

关于环境变量:

1.让子进程继承父进程全部的环境变量

2.可以传递全新的环境变量(自己定义,自己传送)

比如shell最开始就将自己的环境变量传入给自己创建的子进程。

六、新增环境变量

我们使用putenv这个函数新增环境变量。

这个函数是我们直接在程序里面写,之后就会默认追加。我们将other.c代码修改为打印环境变量,之后使用putenv函数新增环境变量给创建的子进程。

程序替换不影响命令行参数和环境变量。

七、系统调用的函数

我们刚才使用的都是C的库函数,真正的系统调用函数是execve函数。

总结:

我们已经知道了如何进行程序替换,这其实是一个很重要的概念,我们以后其实会用很多。接下来我们要利用已学的知识完成一个自己的shell程序。是不是非常期待,对,这部分很烦,但是必须跟下来,下一章继续!


http://www.ppmy.cn/devtools/164385.html

相关文章

项目准备(flask+pyhon+MachineLearning)- 3

目录 1.商品信息 2. 商品销售预测 2.1 机器学习 2.2 预测功能 3. 模型评估 1.商品信息 app.route(/products) def products():"""商品分析页面"""data load_data()# 计算当前期间和上期间current_period data[data[成交时间] > data[成…

k8s新增Node节点 简单易上手 如何给k8s新添加node节点

1、集群环境初始化 机器数量: 1台、操作系统: CentosStream9 、分别设置主机名称为&#xff1a;no’de-3 [rootmaster app1]# kubectl get nodes NAME STATUS ROLES AGE VERSION node Ready control-plane 96d v1.28.2 node-1 Ready &…

C#快速调用DeepSeek接口,winform接入DeepSeek查询资料 C#零门槛接入DeepSeek C#接入DeepSeek源代码下载

下载地址<------完整源码 在数字化转型加速的背景下&#xff0c;企业应用系统对智能服务的需求日益增长。DeepSeek作为先进的人工智能服务平台&#xff0c;其自然语言处理、图像识别等核心能力可显著提升业务系统的智能化水平。传统开发模式下&#xff0c;C#开发者需要耗费大…

测试的BUG分析

在了解BUG之前,我们要先了解软件测试的生命周期,因为大多数BUG都是在软件测试的过程中被发现的 软件测试的生命周期 在了解 软件测试的生命周期 之前,我们要先了解 软件的生命周期 ,虽然他们之间只差了两个字,但是差距还是很大的 首先是 软件生命周期 ,这个是站在 软件 的角…

LeetCode 0132.分割回文串 II:动态规划

【LetMeFly】132.分割回文串 II&#xff1a;动态规划 力扣题目链接&#xff1a;https://leetcode.cn/problems/palindrome-partitioning-ii/ 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是回文串。 返回符合要求的 最少分割次数 。 示例 …

云服务培训五-数据库服务

如上图所圈&#xff0c;这次主要学习云数据库RDS for MySQL、GaussDB和GeminiDB相关内容。 一、结构化数据、非结构化数据 选择数据库时&#xff0c;首先从模型上分析&#xff0c;是否涉及事务处理、复杂的查询关联&#xff0c;还是数据量大、有并发访问需求。同理&#xff0c;…

Ubuntu 下 nginx-1.24.0 源码分析 - ngx_conf_add_dump

ngx_conf_add_dump 定义在src\core\ngx_conf_file.c static ngx_int_t ngx_conf_add_dump(ngx_conf_t *cf, ngx_str_t *filename) {off_t size;u_char *p;uint32_t hash;ngx_buf_t *buf;ngx_str_node_t *sn;ngx_conf_dump_t *cd;has…

git的恢复命令

右键查看 找到版本的 提交ID git reset --soft c097b534188163194fa0e00a20d9e0f07ad82549