进程控制第二弹(进程程序替换)

文章目录

  • 代码现象
  • 基本原理
  • 多进程版本
    • 实例
    • 基本原理
  • 使用所有的替换方法,并且认识函数的参数含义
    • execl
    • execv
    • execlp、execvp
    • execvpe
  • 总结

在这里插入图片描述

代码现象

#include<stdio.h>    
#include<unistd.h>    int main()    
{    printf("testexec begin! ...\n");    execl("/usr/bin/ls","ls","-l","-a",NULL);                                                                                              printf("testexec end! ...\n");    return 0;    
} 

在这里插入图片描述

程序运行后,调用execl函数后,我们的程序去执行了ls命令,原来的进程中printf("testexec end! ...\n"); 没有执行。

基本原理

当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变

我们知道,进程=内核数据结构+代码数据
程序替换的本质是将当前进程的代码和数据进行替换。

在这里插入图片描述

替换的时候,会不会创建新的进程?
答案是没有!!只不过是拿老程序的壳子执行新程序的代码。

站在被替换进程的角度:本质上是这个程序被加载到内存。使用exec系列函数加载,exec系列函数类似一种Linux上的加载函数。

所以为什么上述现象中,原来的进程中printf("testexec end! ...\n"); 没有执行的原因是,调用execl函数后,去执行ls程序了,原来的代码和数据被替换了。

exec系列函数执行完毕后,后续的代码不见了,因为被替换了,因此没有机会去执行了。

不用关心exec系列函数的返回值,只要替换成功,就不会向后面执行;反之,一定是替换失败。

多进程版本

实例

fork创建子进程,让子进程自己去替换

代码:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>int main()
{printf("testexec begin! ...\n");pid_t id=fork();    if(id==0)                           {    sleep(2);         //child    execl("/usr/bin/ls","ls","-l","-a",NULL);    exit(1);                                                                                               }            //father    int status=0;    pid_t rid=waitpid(id,&status,0);    if(rid>0)    {                printf("father wait success,child,exit code:%d\n",WEXITSTATUS(status));    }          printf("testexec end! ...\n");                                               return 0;
}

现象:

在这里插入图片描述

基本原理

创建子进程,子进程完成的任务:

  1. 让子进程执行父进程代码的一部分
  2. 让子进程执行一个全新的程序

在这里插入图片描述

首先父进程和子进程的PCB、虚拟内存构建好后,通过页表映射到物理内存中。可执行程序testexecl从磁盘中加载到物理内存中。在代码中,子进程执行一个新的程序execl("/usr/bin/ls","ls","-l","-a",NULL);此时有一个ls程序需要从磁盘中加载到物理内存中。之前说过,进程具有独立性,即便是父子进程。将ls加载到物理内存时,需要在数据层面上做写时拷贝,然后把ls数据加载进去,修改子进程的映射关系,保证子进程和父进程在数据层面上是独立的。但是ls不仅仅只有数据,还有代码,因此代码也需要发生写时拷贝。虽然代码是可读的,但是在操作系统看来都无所谓。所以重新开辟内存,将ls代码加载到物理内存,修改子进程的映射关系。至此,只要程序替换成功,彻底将子进程和父进程分开了。

使用所有的替换方法,并且认识函数的参数含义

在这里插入图片描述

execl

在这里插入图片描述

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

execl中,l:list,列表

path:需要执行的路劲,需要带路劲
后面的参数:在命令行中怎么执行

例如:

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

在这里插入图片描述


execv

在这里插入图片描述

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

v(vector) : 参数用数组

 if(id==0)    {    sleep(2);    char* const argv[]={"ls","-l","-a","--color",NULL};    //child    // execl("/usr/bin/ls","ls","-l","-a",NULL);    execv("/usr/bin/ls",argv);                                                                                                         exit(1);    }    

在这里插入图片描述


execlp、execvp

execlp(const char *file, const char *arg, ...);
execvp(const char *file, char *const argv[]);

p(path) : 有p自动搜索环境变量PATH,用户可以不传要执行的路劲(但是文件名要传),直接告诉要执行谁即可

if(id==0)    {    sleep(2);    char* const argv[]={"ls","-l","-a","--color",NULL};    //child    // execl("/usr/bin/ls","ls","-l","-a",NULL);    // execv("/usr/bin/ls",argv);    execvp("ls",argv);                                                                                                                 exit(1);    }    

在这里插入图片描述


execvpe

上面的程序替换,我们替换的都是系统的命令,那么可不可以替换我们自己写的程序呢?

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

e(env) : 表示自己维护环境变量

在这里插入图片描述

testexec二进制程序去执行mypragma二进制程序

mypragma.cc代码:

在这里插入图片描述

 if(id==0)    {    sleep(2);    execl("./mypragma","mypragma",NULL);                                                                                                 // sleep(2);    // char* const argv[]={"ls","-l","-a","--color",NULL};    //child    // execl("/usr/bin/ls","ls","-l","-a",NULL);    // execv("/usr/bin/ls",argv);    // execvp("ls",argv);    exit(1);    }    

在这里插入图片描述

此时,我们写的C++程序就被调度了

除了C++语言可以被C语言调度,其他语言也可以被调度,例如python、脚本语言等…

我们知道了这一件事情之后,再谈execvpe函数:

testecel.c文件部分代码:

if(id==0)    {    char* const argv[]={(char*)"mypragma",NULL};    char* const envp[]={(char*)"HAHA=111",(char*)"HEHE=222",NULL};    sleep(2);    // execl("./mypragma","mypragma",NULL);    execvpe("./mypragma",argv,envp);                                                                                                     // sleep(2);    // char* const argv[]={"ls","-l","-a","--color",NULL};    //child    // execl("/usr/bin/ls","ls","-l","-a",NULL);    // execv("/usr/bin/ls",argv);    // execvp("ls",argv);    exit(1);    }    

mypragma.cc代码:

 #include<iostream>    using namespace std;    W>int main(int argc,char* argv[],char* env[])    {    int i=0;    for(;argv[i];i++)    {    printf("argv[%d]:%s\n",i,argv[i]);    }    printf("-----------------------------------\n");    for(i=0;env[i];i++)    {    printf("env[%d]:%s\n",i,env[i]);                                                                                                   }    printf("-----------------------------------\n");    cout<<"hellp C++,I am a C++ pragma!!"<<endl;    cout<<"hellp C++,I am a C++ pragma!!"<<endl;    cout<<"hellp C++,I am a C++ pragma!!"<<endl;    cout<<"hellp C++,I am a C++ pragma!!"<<endl;    cout<<"hellp C++,I am a C++ pragma!!"<<endl;    return 0;    } 

运行结果:

在这里插入图片描述

结论:我们平时自己运行的程序,命令行参数和环境变量是父进程给你的,父进程自己有一个环境变量表,创建子进程时把对应的信息传递给子进程,execvpe直接交给子进程,环境变量就直接给了子进程。

父进程本身就有一批环境变量,从“爷爷进程”来的,即bash

在这里插入图片描述
在这里插入图片描述

这个传参,如果传的是自定义的环境变量,那么就整体替换所有环境变量

传环境变量有三种情况:

  1. 用全新的给子进程
  2. 用老的环境变量给子进程,environ
  3. 老的环境变量稍作修改,传递给子进程

总结

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

数据安全全面防护

what 通过采用各种有效技术和管理措施来保护网络系统的正常运行&#xff0c;从而保证数据的可用性&#xff0c;机密性&#xff0c;完整性。 ---网络安全防护体系建设三同步--规划 建设 运行 数据安全的三大基本特征 可用性 数据在需要时可用且可访问&#xff0c;为实现可用…

算法课程笔记——STL键值对map

map当下标无限的数组 重点是对应关系&#xff0c;一般不修改compare 类比set 没有lowerbound&#xff0c;因为遍历是无序的 ; map不能用sort函数排序 但可用vector转化为map使用 std::set<std::pair<TKEY, mutable TVAL> > ≈ std::map<TKEY, TVAL>

【剪映专业版】13快速为视频配好音:清晰、无噪声、对齐

视频课程&#xff1a;B站有知公开课【剪映电脑版教程】 使用场景&#xff1a;视频无声音或者视频有声音但是需要更改声音 时间指示器在哪里&#xff0c;就从哪里开始 红色按钮&#xff1a;开始录音 声音波纹&#xff1a;蓝色最佳&#xff0c;黄色或红色声音太大&#xff0c;…

Unity UGUI透明区域点击无效

是这样的&#xff0c;我有一张图&#xff0c;客户给的是1920*1080&#xff0c;但只有中间部分是按钮&#xff0c;是有效像素。为了让空白区域点击无效。需要设置如下 并且加上下面这句 this.GetComponent<Image>().alphaHitTestMinimumThreshold 0.1f;

python学习笔记B-08:序列结构之列表--列表的遍历操作

列表的遍历方法主要有三种&#xff0c;使用方法和特点如下&#xff1a; lst list("hello") print("第一种遍历方式&#xff0c;使用for循环&#xff0c;循环变量item直接就是lst中的元素") for item in lst:print(item,end"\t")print("\n…

第64天:服务攻防-框架安全CVE复现Apache ShiroApache Solr

目录 思维导图 案例一&#xff1a;Apache Shiro-组件框架安全 shiro反序列化 cve_2016_4437 CVE-2020-17523 CVE-2020-1957 案例二&#xff1a;Apache Solr-组件框架安全 远程命令执行 RCE&#xff08;CVE-2017-12629&#xff09; 任意文件读取 AND 命令执行&#xff08…

【java】(软考)面向对象---责任链解析

目录 责任链的意义 手写笔记 ​编辑 责任链的意义 当您把请求给出时&#xff0c;如果某对象不能实现您的操作&#xff0c;责任链会自动把您的请求传给它的下一级 从而避免请求的发送者和接受者之间的耦合关系 这里以2007年下半年试题七进行说明 题目描述 某企业的采购审批…

SpringBoot学习之Kafka下载安装和启动(三十三)

一、Mac环境 1、下载Kafka&#xff1a;Apache Kafka 2、这里我选择的版本是kafka_2.12-3.7.0&#xff0c;下载最新版的Kafka二进制文件&#xff0c;解压到你喜欢的目录&#xff08;建议目录不要带中文&#xff09;。 3、启动ZooKeeper服务&#xff0c;Kafka需要使用ZooKeeper&…

OpenHarmony 网络管理-Socket连接

介绍 本示例主要演示了Socket在网络通信方面的应用&#xff0c;展示了Socket在两端设备的连接验证、聊天通信方面的应用。 效果预览 使用说明 1.搭建服务器环境&#xff1a;修改服务器脚本中的服务端IP地址&#xff0c;与本机IP地址保持一致&#xff0c;修改完成后双击运行脚…

Zynq 7000 系列中的JTAG和DAP子系统

Zynq 7000系列SoC器件通过标准JTAG调试接口提供调试访问。在内部&#xff0c;SoC设备器件在处理系统&#xff08;PS&#xff09;内部实现了一个Arm调试访问端口&#xff08;DAP&#xff09;&#xff0c;同时在可编程逻辑&#xff08;PL&#xff09;内部实现了一个标准的JTAG测试…

minio如何配置防盗链

MinIO 是一个开源的对象存储服务器&#xff0c;用于存储大量的数据&#xff0c;同时提供了丰富的功能和 API。配置防盗链可以帮助你控制谁可以访问存储在 MinIO 上的对象。以下是在 MinIO 中配置防盗链的一般步骤&#xff1a; 编辑 config.json 文件&#xff1a; 找到 MinIO 服…

每日昨日之螺旋矩阵

螺旋矩阵 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5] 示例 2&#xff1a; 输入&#xff1a;…

文心一言 VS 讯飞星火 VS chatgpt (241)-- 算法导论17.3 7题

七、为动态整数多重集 S (允许包含重复值)设计一种数据结构&#xff0c;支持如下两个操作&#xff1a;① INSERT(S,x) 将 x 插入 S 中&#xff1b;② DELETE-LARGER-HALF(S) 将最大的 ⌈|S|/2⌉ 个元素从S中删除。解释如何实现这种数据结构&#xff0c;使得任意 m 个 INSERT 和…

spring高级篇(二)

1、Aware和InitializingBean Aware和InitializingBean都与Bean的生命周期管理相关。 Aware接口: 概念: Aware接口是Spring框架中的一个标记接口&#xff0c;它表示一个类能够感知到&#xff08;aware of&#xff09;Spring容器的存在及其特定的环境。Spring框架提供了多个Awar…

sublime运行编译C和Java

1.先安装终端 参照以下教程 如何在 Sublime 文本编辑器中使用终端&#xff1f;_sublime终端窗口怎么打开-CSDN博客 可能遇到的问题&#xff1a;有些sublime text3可能并没有显示“package control”。这个问题对于笔者来说是有些吊诡的&#xff0c;因为之前一开始安装时是能…

【大模型系列】大模型评价指标总结

文章目录 1 图生文 (Image-to-Text)1.1 BLEU&#xff1a;基于准确率&#xff0c;得分越高越好1.2 METEOR&#xff1a;基于准确率和召回率&#xff0c;得分越高越好1.3 ROUGE&#xff1a;得分越高越好1.4 CIDEr&#xff1a;得分越高越好1.5 SPICE&#xff1a;得分越高越好1.6 Hu…

文本美学:text-image打造视觉吸引力

当我最近浏览 GitHub 时&#xff0c;偶然发现了一个项目&#xff0c;它能够将文字、图片和视频转化为文本&#xff0c;我觉得非常有趣。于是我就花了一些时间了解了一下&#xff0c;发现它的使用也非常简单方便。今天我打算和家人们分享这个发现。 项目介绍 话不多说&#xf…

4.2冰达机器人:视觉实例-机器人视觉循线、视觉实例-调整循线颜色

4.2.10a视觉实例-机器人视觉循线 本节内容演示一个机器人视觉的视觉循线实例 准备工作&#xff1a;布置一块区域作为循线场所&#xff0c;如下图所示。用蓝色胶带在地面贴一条路线&#xff08;机器人极限转弯半径0.5m&#xff0c;不要贴得过于曲折&#xff09;&#xff0c;将…

【超级简单】vscode进入服务器的docker容器

前提 1、已经运行docker容器 2、已经用vscode链接服务器 在vscode中安装的插件 Dev Containers docker 在容器中安装的依赖 yum install openssh-server yum install openssh-clientsvscode进入服务器的docker容器 找到自己的容器&#xff0c;右键点击&#xff0c;找到…

苍穹外卖day1--开发环境搭建

整体结构 前端&#xff1a;管理端&#xff08;Web&#xff09; 用户端&#xff08;小程序&#xff09; 后端&#xff1a;后端服务&#xff08;Java&#xff09; 前端工程基于ngnix运行 启动nginx&#xff1a;双击nginx.exe即可启动nginx服务&#xff0c;访问端口号为80 后端…