【Linux】开始学习进程替换吧!

在这里插入图片描述
送给大家一句话:
人生中有些事,你不竭尽所能去做,你永远不知道你自己有多出色。—— 尾田荣一郎《海贼王》

开始学习进程替换吧

  • 1 前言
  • 2 进程替换
    • 2.1 替换函数
    • 2.2 替换原理
    • 2.3 单进程改为多进程
    • 2.4 理解使用exec* 函数
      • int execl (const char *path, const char *arg, ...)
      • int execv (const char *path, char *const argv[])
      • int execvp(const char *file, char *const argv[])
      • int execle(const char *path, const char *arg, ...,char *const envp[])
      • int execvpe(const char *filename, char *const argv[],char* const envp[])
      • 注意
  • Thanks♪(・ω・)ノ谢谢阅读!!!
  • 下一篇文章见!!!

1 前言

通过学习进程替换,我们可以体会到多语言混搭的快乐,可以从C语言直接蹦到python ,也可以从c++里运行java代码。是不是很厉害!这是通过调度多个进程的效果,联系我们之前学习的进程,进程控制等概念。我们可以想要运行其他代码可以通过创建子进程来实现,但是这样也肯定是同一种语言,如果想要运行其他语言,那是不是有种方法可以调度一个进程来当做子进程呢???
我们开始今天的学习吧!

2 进程替换

2.1 替换函数

进程替换有六种以exec开头的函数,统称exec函数:

#include <unistd.h>`
int execl(const char *path, const char *arg, ...);//...代表可变参数 类似printf
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 *filename, char *const argv[],char* const envp[]);

我们来进行一下使用,来看看:

  1 #include<stdio.h>2 #include<unistd.h>3 4 int main()5 {6   printf("textexec ... begin!\n");7 8   execl("/usr/bin/ls","ls","-l","-a",NULL);                                                                                                                                   9                                                                                                10   printf("textexec ... end!\n");                                                               11   return 0;                                                                                    12 }  

在这里插入图片描述
可以看到执行了ls -l -a命令(最后的打印语句也没有进行),可是我执行的是我们的代码,怎么就运行了ls 这个程序呢?
原因就是:exec*系列函数可以执行起来新的程序,让进程通过exec函数把自己替换为一个全新的进程

2.2 替换原理

  • 用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支)
  • 子进程往往要调用一种exec函数以执行另一个程序。
  • 当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动 开始执行
  • 调用exec并不创建新进程,所以调用exec前后该进程的id并未改变
  • 没有创建新进程!!!

在这里插入图片描述
我们知道 进程 = 内核数据结构 + 代码和数据 ,替换就是用新进程的代码与数据替换之前的代码与数据,注意不改变pid哦!
站在被替换进程的角度:本质就是这个程序别加载到内存里了!!!exec* 就类似一个Linux 上的加载函数。

而且我们不用关心exec*函数的返回值,只要替换成功了,就不会向后运行(也就用不到它的返回值了),只要继续运行那一定就是替换失败了!!!
那如果不想替换掉我们的程序,还想要打开一个新程序呢??? 我们接着向下看

2.3 单进程改为多进程

方法很简单,我们通过fork函数创建一个子进程,让子进程来执行我们的新程序不就可以了吗!

1 #include<stdio.h>  2 #include<unistd.h>   3 #include<stdlib.h>4 #include<sys/types.h>5 #include<sys/wait.h>6 7 8 int main()9 {10   printf("textexec ... begin!\n");11   12   pid_t id = fork();13   if(id == 0)14   {15     //child16     execl("/usr/bin/ls","ls","-l","-a",NULL);17     exit(1);18   }19 20   int status = 0;21   pid_t rid = waitpid(-1,&status,0);22 23   if(rid > 0)24   {25     printf("father wait success,child exit code:%d \n",WEXITSTATUS(status));                                                                                                  26   }                                                                                                                     27   printf("testexec ... end!\n");                                                                                        28                                                                                                                         29   return 0;                                                                                                             30 }          

这个程序中:我们通过fork创建了一个子进程,然后在子进程中进行进程替换。这样应该就可以运行ls命令还不会影响原本程序。来看效果:
在这里插入图片描述
那么这样以后,创建子进程就变得非常有用了。我们可以通过子进程来完成对应任务:

  1. 让子进程完成父进程代码的一部分
  2. 让子进程执行一个全新的程序(会发生写时拷贝,建立全新的物理内存空间)

2.4 理解使用exec* 函数

这些函数原型看起来很容易混,但只要掌握了规律就很好记。

  • l(list) : 表示参数采用列表
  • v(vector) : 参数用数组
  • p(path) : 有p自动搜索环境变量PATH
  • e(env) : 表示自己维护环境变量

int execl (const char *path, const char *arg, …)

l 表示列表 list
两个参数分别代表:

  1. path (你想执行谁) : 我们执行的程序需要带路径
  2. arg(你想怎么执行) : 咳传多个 , 命令行里怎么运行就怎么写入!!! 举个例子:ls -a -l 所以我们传execl(“/usr/bin/ls” , “ls”,“-a”,“-l”) 。这样就像命令列表

通过这些函数也可以进行执行我们缩写的程序!!!

int execv (const char *path, char *const argv[])

v 表示数组 vector
这个方法就是把列表整合为一个数组,这样就直接传入一个数组(必须以NULL结尾!!!)就可以了:

char* const argv[] = 
{(char*)"ls",(char*)"-a",(char*)"-l",(char*)"--color",NULL
};
execv("/usr/bin/ls",argv);

是不是很想之前了解过的main函数参数!

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

带p含义是可以不传入文件路径,可以直接告诉exec*需要执行谁就可以了
本质就是:查找这个程序,系统会在系统环境变量PATH中的路径来寻找

char* const argv[] = 
{(char*)"ls",(char*)"-a",(char*)"-l",(char*)"--color",NULL
};
execvp("ls",argv);

这个 int execlp(const char *file, const char *arg, …) 同理!!!

execlp("ls" , "ls","-a","-l") 

int execle(const char *path, const char *arg, …,char *const envp[])

这个就就加上了环境变量,让我们支持自主传入

int execve(const char *filename, char const argv[],char const envp[]) 同理 !!!

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

这让我们可以传入环境变量给子进程!!!当然也会有一批来着"爷爷进程"bash的环境变量!
envp的含义是全体替换环境变量,所以会有以下情况:

  1. 用全新的给子进程
  2. 用老的环境变量给子进程 char** environ
  3. 老的环境变量稍微修改传给子进程 调用 putenv ()函数
char* const argv[] = 
{(char*)"ls",(char*)"-a",(char*)"-l",(char*)"--color",NULL
};
//用全新的给子进程
char* const envp[] = 
{(char*)"HAHA=111111",(char*)"HEHE=222222",NULL
};
//putenv("HAHA=111111")
//putenv("HEHE=222222");
//老的环境变量稍微修改传给子进程execvpe("./myprocess",argv , encp);
//char** environ
// execvpe("./myprocess",argv , environ);

注意

根据上面的用法使用,我们可以总结一下:

函数名参数格式是否带路径是否使用当前环境变量
execl列表不是
execlp列表
execle列表不是不是,需要自己组装环境变量
execv数组不是
execvp数组
execve数组不是不是,需要自己组装环境变量

而且只有 execle 是系统调用!!!他们的关系如下:
在这里插入图片描述

Thanks♪(・ω・)ノ谢谢阅读!!!

下一篇文章见!!!

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

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

相关文章

【独立开发前线】Vol.25 Dogacade-通过SEO,每个月13万的访问量

今天要给大家分享的一个案例网站是&#xff1a;Dogacade 网址是&#xff1a;Dog Academy - Home 这是一个提供狗狗训练服务的网站&#xff0c;网站的宣传语是&#xff1a;在短短 4 周内培育出您梦想中的听话、乖巧的狗狗。 网站的流量非常不错&#xff0c;在这么垂直利基的市…

链表中两两交换结点(力扣24)

文章目录 题目题解一、思路二、解题方法三、Code 总结 题目 Problem: 24. 两两交换链表中的节点 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交…

24/03/28总结

抽象类&#xff1a; 将共性的方法抽取到父类之后。由于每一个子类执行的内容是不一样&#xff0c;所以&#xff0c;在父类中不能确定具体的方法体。该方法就可以定义为抽象方法。 而为什么不直接在子类中定义方法&#xff1a;项目的完成不是一个人&#xff0c;如果有时忘记写方…

BaseDao封装增删改查

文章目录 什么是BaseDao操作代码增删改查询单个数据查询多个数据 总结 什么是BaseDao BaseDao是&#xff1a; 数据库里负责增加&#xff0c;删除&#xff0c;修改&#xff0c;查询 具体来说是一种接口代码,公共方法的接口类。 在dao层新建basedao,其他dao层接口继承basedao 相…

python函数参数中独立星号*的作用

python函数中间有一个&#xff08;&#xff09;分隔&#xff0c;星号后面为*命名关键字参数&#xff0c;星号本身不是参数**。命名关键字参数&#xff0c;在函数调用时必须带参数名字进行调用。如下例子&#xff1a;

【Netty 源码】NioEventLoop 源码分析 篇二

【Netty 源码】NioEventLoop 源码分析 篇二 1.NioEventLoop 继承关系 NioEventLoop继承自SingleThreadEventLoop&#xff0c;一次只能执行一个线程任务&#xff0c;因此在父类SingleThreadEventLoop中维护了 Queue tailTasks 线程队列。 NioEventLoop又间接继承了 AbstractS…

六千字详解!一篇看懂 ArrayList 的扩容机制(完整源码解析)

☀️今天花了很久写了这篇关于 ArrayList 扩容机制源码解析的博客&#xff0c;在阅读源码的过程中发现了很多之前有误解的地方&#xff0c;也加深了对代码的理解&#xff0c;所以写下了这篇博客。 &#x1f3b6;本文附带了流程中所有的代码和附加解析&#xff0c;我有信心一定能…

五款常用在线JavaScript加密混淆工具详解:jscrambler、JShaman、jsfack、ipaguard和jjencode

摘要 本篇技术博客将介绍五款常用且好用的在线JavaScript加密混淆工具&#xff0c;包括 jscrambler、JShaman、jsfack、freejsobfuscator 和 jjencode。通过对这些工具的功能及使用方法进行详细解析&#xff0c;帮助开发人员更好地保护和加密其 JavaScript 代码&#xff0c;提…

STM32之HAL开发——串口配置(CubeMX)

串口引脚初始化&#xff08;CubeMX&#xff09; 选择RCC时钟来源 选择时钟频率&#xff0c;配置为最高频率72MHZ 将单片机调试模式打开 SW模式 选择窗口一配置为异步通信模式 点击IO口设置页面&#xff0c;可以看到当前使用的串口一的引脚。如果想使用复用功能&#xff0c;只需…

原型链-(前端面试 2024 版)

来讲一讲原型链 原型链只存在于函数之中 四个规则 1、引用类型&#xff0c;都具有对象特性&#xff0c;即可自由扩展属性。 2、引用类型&#xff0c;都有一个隐式原型 __proto__ 属性&#xff0c;属性值是一个普通的对象。 3、引用类型&#xff0c;隐式原型 __proto__ 的属…

Vue——案例01(查询用户)

一、案例实现页面 二、案例实现效果 1. 查询效果 2. 年龄升序 3. 年龄降序 4. 原顺序 三、案例实现思路 1. 定义界面所需标签样式 <div id"app"><h2>查询用户:</h2><input type"text" placeholder"请输入名字"/><b…

代码随想录算法训练营第35天| 435. 无重叠区间、763.划分字母区间、56. 合并区间

435. 无重叠区间 题目链接&#xff1a;无重叠区间 题目描述&#xff1a;给定一个区间的集合 intervals &#xff0c;其中 intervals[i] [starti, endi] 。返回 需要移除区间的最小数量&#xff0c;使剩余区间互不重叠 。 解题思想&#xff1a; 这道题目和射气球很像。 *“需…