当前位置: 首页 > news >正文

七、进程程序替换

文章目录

  • 一、进程程序替换
    • (一)概念
    • (二)为什么程序替换
    • (三)程序替换的原理
    • (四)如何进行程序替换
      • 1. execl
      • 2. 引入进程创建——子进程执行程序替换,会不会影响父进程呢?
    • (五)大量的测试各种不同的接口
      • 1.命名理解 (带v和带l的)
      • 2.记忆技巧
      • 3.带e和带p
    • (六)具体接口说明
      • 1.execv
      • 2.execlp
      • 3.execvp
      • 4.execle
  • 二、模拟实现shell
  • 三、内建命令——以chdir为例

一、进程程序替换

(一)概念

子进程执行的是父进程的代码片段,如果我们想让创建出来的子进程,执行全新的程序呢?

需要用到:进程的程序替换!

(二)为什么程序替换

我们一般在服务器设计(linux编程)的时候,往往需要子进程干两件种类事情!

  1. 让子进程执行父进程的代码片段(服务器代码)
  2. 让子进程执行磁盘中一个全新的程序(shell,想让客户端执行对应的程序,通过我们的进程,执行其他人写的进程代码等等),c/c++ ->c/c++/Python/Shell/Php/Java…

(三)程序替换的原理

  1. 将磁盘中的程序,加载入内存结构
  2. 重新建立页表映射,谁执行程序替换,就重新建立谁的映射(子进程)

效果:让我们的父进程和子进程彻底分离,并让子进程执行一个全新的程序!

在这里插入图片描述

这个过程有没有创建新的进程呢?

没有,子进程的PCB等结构并未改变,只是改变的页表映射关系。

程序替换成功后,运行完新程序,则程序直接退出;程序替换成功后,原进程没有退出,使用原进程运行新程序

我们只能调用接口,为什么呢?

因为这个过程实际上是把数据从一个硬件搬到另一个硬件的操作,这个操作只能由OS操作系统完成

(四)如何进行程序替换

man execl 查看进行程序替换的函数:
我们如果要执行一个全新的程序,我们需要做几件事情呢?

1.程序本质就是一个磁盘上的文件,所以我们需要先找到这个程序在哪里
2.程序可能携带选项进行执行(也可以不携带),然后告诉OS,我要怎么执行这个程序?(要不要带选项)

命令行怎么写(ls -l -a), 这个参数就怎么填"ls",“-l”,“-a”,最后必须是NULL,标识参数传递完毕[如何执行程序的]
00

 #include <unistd.h>extern char **environ;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 execvpe(const char *file, char *const argv[],char *const envp[]);

1. execl

makefile

myexec:myexec.cg++ -o $@ $^ -std=c++11 
.PHONY:clean
clean:rm -f myexec

myexec.c

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<assert.h>
#include<sys/types.h>
#include<sys/wait.h>int main(int argc,char *argv[]) {printf("process is running...\n");pid_t id  = fork();assert(id != -1);if (id == 0) {sleep(1);printf("我是一个进程,我的pid是:%d\n",getpid());// 执行ls -l -a 命令//execl("/usr/bin/ls","ls","-l","-a",NULL); // 这里有两个ls, 重复吗?不重复,一个是告诉系统我要执行谁?一个是告诉系统,我想怎么执行// 执行top命令execl("/usr/bin/top","top",NULL);               printf("我执行完毕了,我的pid是:%d\n",getpid());      // 执行完以上的代码,我们发现一个问题!!// 最后一句代码为什么没有被打印出来呢!!!}return 0;
}

在这里插入图片描述
因为进程一旦替换成功,是将当前进程的代码和数据全部替换了!!!

后面的printf是代码吗??有没有被替换呢??当然,已经早就被替换了!!该代码不存在了!!

所以这个程序替换函数,用不用判断返回值?为什么?

答:不用判断返回值,因为只要成功了,就不会有返回值execl,一旦替换成功,是将当前进程的所有代码和数据全部替换了,execl就直接执行ls命令的代码去了。。而失败的时候,必然会继续向后执行!!最多通过返回值得到什么原因导致的替换失败!

2. 引入进程创建——子进程执行程序替换,会不会影响父进程呢?

子进程执行程序替换,会不会影响父进程呢? ?

不会,因为进程具有独立性。
为什么,如何做到的? ?数据层面发生写时拷贝!当程序替换的时候,我们可以理解成为:代码和数据都发生了写时拷贝完成父子的分离!

(五)大量的测试各种不同的接口

1.命名理解 (带v和带l的)

这些函数原型看起来很容易混,但只要掌握了规律就很好记。l(list) : 表示参数采用列表v(vector) : 参数用数组p(path) : 有p自动搜索环境变量PATHe(env) : 表示自己维护环境变量

2.记忆技巧

execl结尾 l 为list,列表传参——>可变参数包,一个一个传。execv结尾 v 为vector,数组传参——>传的是指针数组。

3.带e和带p

带e的都是可以传环境变量的(execle,execvpe)但是会覆盖系统原有的环境变量,把自己传的环境变量交给进程;
不带e是默认继承系统的环境变量;带p的都是可以自带路径的,直接传命令名称即可(execlp,execvp,execvpe)

(六)具体接口说明

1.execv

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

path 依然是程序的路径,参数 argv[] 是存着要实现指令的指针数组
在这里插入图片描述

char *const argv_[] = {"ls","-a","-l","--color=auto",NULL
};

2.execlp

int execlp(const char *file, const char *arg, ...);        带p的就传程序名即可file:要执行的程序。执行指令的时候,默认的搜索路径,在哪里搜索呢?在环境变量PATH
命名带p的,可以不带路径,只说出你要执行哪一个程序即可!execlp("ls""ls", "-a", "-1 "NULL)
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<assert.h>
#include<sys/types.h>
#include<sys/wait.h>int main(int argc,char *argv[]) {printf("process is running...\n");pid_t id  = fork();assert(id != -1);if (id == 0) {sleep(1);printf("我是一个进程,我的pid是:%d\n",getpid());//execl("/usr/bin/ls","ls","-l","-a",NULL); // 这里有两个ls, 重复吗?不重复,一个是告诉系统我要执行谁?一个是告诉系统,我想怎么执行// 执行top命令char *const argv_[]={(char*)"ls",(char*)"-a",(char*)"-l",NULL};//execl("/usr/bin/top","top",NULL);         execlp("ls","ls","-a","-l",NULL);//这里出现了两个ls,含义一样吗?不一样!exit(1);   //execvp("ls", argv_);printf("我执行完毕了,我的pid是:%d\n",getpid());      // 执行完以上的代码,我们发现一个问题!!// 最后一句代码为什么没有被打印出来呢!!!}int status = 0;int ret = waitpid(id,&status,0);if(ret == id){sleep(2);printf("父进程等待成功!\n");}return 0;
}

在这里插入图片描述

3.execvp

 int execvp(const char *file, char *const argv[]);
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<assert.h>
#include<sys/types.h>
#include<sys/wait.h>int main(int argc,char *argv[]) {printf("process is running...\n");pid_t id  = fork();assert(id != -1);if (id == 0) {sleep(1);printf("我是一个进程,我的pid是:%d\n",getpid());//execl("/usr/bin/ls","ls","-l","-a",NULL); // 这里有两个ls, 重复吗?不重复,一个是告诉系统我要执行谁?一个是告诉系统,我想怎么执行// 执行top命令char *const argv_[]={(char*)"ls",(char*)"-a",(char*)"-l",NULL};//execl("/usr/bin/top","top",NULL);         //execlp("ls","ls","-a","-l",NULL);//这里出现了两个ls,含义一样吗?不一样!exit(1);   execvp("ls", argv_);printf("我执行完毕了,我的pid是:%d\n",getpid());      // 执行完以上的代码,我们发现一个问题!!// 最后一句代码为什么没有被打印出来呢!!!}// 父进程int status = 0;int ret = waitpid(id,&status,0);if(ret == id){sleep(2);printf("父进程等待成功!\n");}return 0;
}

在这里插入图片描述

4.execle

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

这里的前几个接口都非常熟悉了,这里最后一个接口叫做环境变量。那么为什么要有这个接口呢?

说到环境变量之前我们先来看一下这个问题,我们刚刚提到过,进程替换可以让我们执行其他语言写的程序,那么我们怎么来执行呢?(我们使用execl 函数来调用)

我们现在的目标是想用我们写的myexec.c把mycmd.cpp调用起来,那么怎么来用呢?
myexec.c

我们当前使用的是绝对路径来调用我的mycmd程序!

当然我们也可以使用相对路径来调用。

相对路径调用——
makefile

.PHONY:all
all: mybin myexec
mybin:mybin.cg++ -o $@ $^ -std=c++11
myexec:myexec.cg++ -o $@ $^ -std=c++11
.PHONY:clean
clean:rm -f myexec mybin
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>int main()
{printf("我是一个进程,我的pid是:%d\n",getpid());pid_t id=fork(); if(id==0){//childprintf("我是子进程,我的pid是:%d\n",getpid());execl("./mycmd","mycmd",NULL);exit(1);}//一定是父进程int status=0;int ret=waitpid(id,&status,0);if(ret==id){sleep(2);printf("父进程等待成功!\n");}return 0;
}

在这里插入图片描述
为什么会有这么多接口?——因为要适配应用场景。

execve为什么是单独的?——实际上,只有 execve是系统调用,其他都是对系统接口的封装,最后都要调用到execve!
在这里插入图片描述

二、模拟实现shell

三、内建命令——以chdir为例

相关文章:

七、进程程序替换

文章目录 一、进程程序替换&#xff08;一&#xff09;概念&#xff08;二&#xff09;为什么程序替换&#xff08;三&#xff09;程序替换的原理&#xff08;四&#xff09;如何进行程序替换1. execl2. 引入进程创建——子进程执行程序替换&#xff0c;会不会影响父进程呢? &…...

C++核心编程——详解运算符重载

文章目录&#x1f4ac; 一.运算符重载基础知识①基本概念②运算符重载的规则③运算符重载形式④运算符重载建议 二.常用运算符重载①左移(<<)和右移(>>)运算符重载1️⃣重载后函数参数是什么&#xff1f;2️⃣重载的函数返回类型是什么&#xff1f;3️⃣重载为哪种…...

2023年前端面试汇总-CSS

1. CSS基础 1.1. CSS选择器及其优先级 对于选择器的优先级&#xff1a; 1. 标签选择器、伪元素选择器&#xff1a;1&#xff1b; 2. 类选择器、伪类选择器、属性选择器&#xff1a;10&#xff1b; 3. id 选择器&#xff1a;100&#xff1b; 4. 内联样式&#xff1a;1000&a…...

Java调用Pytorch实现以图搜图(附源码)

Java调用Pytorch实现以图搜图 设计技术栈&#xff1a; 1、ElasticSearch环境&#xff1b; 2、Python运行环境&#xff08;如果事先没有pytorch模型时&#xff0c;可以用python脚本创建模型&#xff09;&#xff1b; 1、运行效果 2、创建模型&#xff08;有则可以跳过&#xf…...

【EasyX】实时时钟

目录 实时时钟1. 绘制静态秒针2. 秒针的转动3. 根据实际时间转动4. 添加时针和分针5. 添加表盘刻度 实时时钟 本博客介绍利用EasyX实现一个实时钟表的小程序&#xff0c;同时学习时间函数的使用。 本文源码可从github获取 1. 绘制静态秒针 第一步定义钟表的中心坐标center&a…...

基于XC7Z100的PCIe采集卡(GMSL FMC采集卡)

GMSL 图像采集卡 特性 ● PCIe Gen2.0 X8 总线&#xff1b; ● 支持V4L2调用&#xff1b; ● 1路CAN接口&#xff1b; ● 6路/12路 GMSL1/2摄像头输入&#xff0c;最高可达8MP&#xff1b; ● 2路可定义相机同步触发输入/输出&#xff1b; 优势 ● 采用PCIe主卡与FMC子…...

Kibana:使用 Kibana 自带数据进行可视化(一)

在今天的练习中&#xff0c;我们将使用 Kibana 自带的数据来进行一些可视化的展示。希望对刚开始使用 Kibana 的用户有所帮助。 前提条件 如果你还没有安装好自己的 Elastic Stack&#xff0c;你可以参考如下的视频来开启 Elastic Stack 并进行下面的练习。你可以开通阿里云检…...

MySQL数据库基础 07

第七章 单行函数 1. 函数的理解1.1 什么是函数1.2 不同DBMS函数的差异1.3 MySQL的内置函数及分类 2. 数值函数2.1 基本函数2.2 角度与弧度互换函数2.3 三角函数2.4 指数与对数2.5 进制间的转换 3. 字符串函数4. 日期和时间函数4.1 获取日期、时间 4.2 日期与时间戳的转换 4.3 获…...

JVM | JVM垃圾回收

JVM | JVM垃圾回收 1、堆空间的基本结构2、内存分配和回收原则2.1、对象优先在 Eden 区分配2.2、大对象直接进入老年代2.3、长期存活的对象将进入老年代2.4、主要进行 gc 的区域2.5、空间分配担保3、死亡对象判断方法3.1、引用计数法3.2、可达性分析算法3.3、引用类型总结3.4、…...

avive零头撸矿

Avive 是一个透明的、自下而上替代自上而下的多元网络&#xff0c;旨在克服当前生态系统的局限性&#xff0c;实现去中心化社会。 aVive&#xff1a;一个基于 SBT 和市场的 deSoc&#xff0c;它使 dapps 能够与分散的位置 oracle 和 SBT 关系进行互操作。您的主权社交网络元宇宙…...

openGauss5.0之学习环境 Docker安装

文章目录 0.前言1. 准备软硬件安装环境1.1 软硬件环境要求1.2 修改操作系统配置1.2.1 关闭操作系统防火墙 1.3 设置字符集参数1.4 设置时区和时间&#xff08;可选&#xff09;关闭swap交换内存1.5 关闭RemoveIPC1.6 关闭HISTORY记录 2. 容器安装2. 1支持的架构和操作系统版本2…...

数据可视化大屏人员停留系统的开发实录(默认加载条件筛选、单击加载、自动刷新加载、异步加载数据)

项目需求 录入进入房间的相关数据&#xff1b;从进入时间开始计时&#xff0c;计算滞留房间的时间&#xff1b;定时刷新数据&#xff0c;超过30分钟的人数&#xff0c;进行红色告警&#xff1b; 实现流程 为了完整地实现上述需求&#xff0c;我们可以按照以下步骤开发&#…...

【Linux】-关于调试器gdb的介绍和使用

作者&#xff1a;小树苗渴望变成参天大树 作者宣言&#xff1a;认真写好每一篇博客 作者gitee:gitee 如 果 你 喜 欢 作 者 的 文 章 &#xff0c;就 给 作 者 点 点 关 注 吧&#xff01; 文章目录 前言一、Linux中的debug和release二、gdb的使用**1.进入调试****2.显示代码*…...

项目开发经验

hadoop 1.namenode中有专门的工作线程池用于处理与datanode的心跳信号 dfs.namenode.handler.count20 * log2(Clust 2.编辑日志存储路径 dfs.namenode.edits.dir 设置与镜像文件存储路径 dfs.namenode分开存放&#xff0c;可以达到提高并发 3.yarn参数调优&#xff0c;单个服…...

STM32——05-按键、时钟控制、中断复位 点亮LED灯

如何点亮一颗LED灯 编程实现点灯 常用的 GPIO HAL 库函数&#xff1a; void HAL_GPIO_Init ( GPIO_TypeDef * GPIOx , GPIO_InitTypeDef * GPIO_Init ); void HAL_GPIO_WritePin ( GPIO_TypeDef * GPIOx , uint16_t GPIO_Pin , GPIO_PinState PinState ); void HAL_GPIO_Togg…...

VBA下载二进制文件,文本读写

这里使用了vba如下两个对象&#xff1a; Microsoft.XMLHTTP&#xff1a;文件读写&#xff0c;可读写二进制&#xff0c;可指定编码,对于utf-8编码文本文件使用FSO的TextStream对象打开&#xff0c;读取到的内容可能会出现乱码&#xff0c;可以使用该对象打开;前期绑定添加引用…...

MongoDB结合Robo 3T 1.4.3的简单操作

MongoDB的简单操作结合Robo 3T 1.4.3工具进行查询。 常用的正则表达式 /* 29 */ 正则表达式 /\* [0-9]* \*/ "_id" : ObjectId("5f3d05cdfd2aa9a8a7"), 正则表达式 \"([^\"]*_id)\".*, 使用方法&#xff1a;查询结果去掉注释和不需要…...

【学习笔记】[AGC048D] Pocky Game

这是一个非平等博弈。但是只要求你判断胜负&#xff0c;本身也不是一道结论题&#xff0c;所以可以用 D P DP DP来解决。 结论&#xff1a;第一堆石子剩的越多&#xff0c;先手玩家获胜的概率越大。这直接引出了一个非常感性的结论&#xff1a;每次取石子时要么取一堆&#xf…...

Qgis中进行Shp和Excel属性连接实现百强县公共预算空间分析

前言 在之前的博文中&#xff0c;将2022的全国百强县一般公共预算收入的数据下载到了本地&#xff0c;博客原文地址&#xff1a;一种使用Java的快速将Web中表格转换成Excel的方法。对于不关注时空位置关系的一般分析&#xff0c;到此也就基本够用了。但是&#xff0c;如果站在全…...

ES6 新增的循环方法

在 ES6&#xff08;ECMAScript 2015&#xff09;中&#xff0c;新增了一些循环方法&#xff0c;这些方法可以帮助我们更方便地遍历数组、字符串、Set、Map 等数据结构。本文将介绍一些常用的 ES6 循环方法。 for…of 循环 for…of 循环是一种遍历可迭代对象的方法&#xff0c…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲

文章目录 前言第一部分&#xff1a;体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分&#xff1a;体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

6.9-QT模拟计算器

源码: 头文件: widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMouseEvent>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);…...

相关类相关的可视化图像总结

目录 一、散点图 二、气泡图 三、相关图 四、热力图 五、二维密度图 六、多模态二维密度图 七、雷达图 八、桑基图 九、总结 一、散点图 特点 通过点的位置展示两个连续变量之间的关系&#xff0c;可直观判断线性相关、非线性相关或无相关关系&#xff0c;点的分布密…...

js 设置3秒后执行

如何在JavaScript中延迟3秒执行操作 在JavaScript中&#xff0c;要设置一个操作在指定延迟后&#xff08;例如3秒&#xff09;执行&#xff0c;可以使用 setTimeout 函数。setTimeout 是JavaScript的核心计时器方法&#xff0c;它接受两个参数&#xff1a; 要执行的函数&…...