九、进程程序替换

news2024/12/22 16:27:59

文章目录

  • 一、进程程序替换
    • (一)概念
    • (二)为什么程序替换
    • (三)程序替换的原理
    • (四)如何进行程序替换
      • 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.c
	g++ -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自动搜索环境变量PATH

e(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.c
	g++ -o $@ $^ -std=c++11
myexec:myexec.c
	g++ -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)
    {
        //child
        printf("我是子进程,我的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为例

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

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

相关文章

016、元组(行)结构与dml操作

元组结构与dml操作 元组(行)结构行头信息Pageinspect工具DML操作InsertionDeletionUpdate块空间清理元组(行)结构 t_xmin保存插入此元组的事务的txid。这一行被哪个事务ID所修改t_xmax保存删除或更新此元组的事务的txid。如果此元组未被删除或更新,则t_xmax设置为0,这意味…

数据结构——堆(C语言实现)

文章目录 什么是堆堆的实现堆的结构定义堆的初始化接口堆的销毁接口堆的插入数据接口向上调整建堆接口判断堆是否为空堆的删除数据接口向下调整建堆接口获取堆顶数据获取堆的有效数据个数完整实现代码小结 堆排序堆排序的实现 关于建堆和堆排序时间复杂度的分析向下调整建堆向上…

STL之string

目录 string的基本实现一. string的基本架构二. 常用方法及实现1.初始化和清理a. 构造函数b. 析构函数c. swapd. 拷贝构造e. operator 2.成员访问a. operator[]b. sizec. c_str 3.迭代器iteratora. beginb. end 4.增删查改a. reserveb. resizec. insertd. push_backe. appendf.…

【连续介质力学】连续体运动学

简介 一个质点从t0出发&#xff0c;随着时间有不同的构形&#xff0c;运动的描述是运动学。 所以需要建立运动方程来表征连续体是如何演化及其性质&#xff08;例如位移、速度、加速度、质量密度、温度等&#xff09;如何随时间变化 初始构形 或者 参考构形&#xff1a; B …

Java反射与注解

文章目录 一、 注解1.简介2. 元注解3. 自定义注解 二、 反射1. 简介2. 理解Class类并获取Class实例3. 类的加载与初始化4. 类加载器ClassLoader5. 获取运行时类的完整结构6. 动态创建对象执行方法7. 反射操作泛型8. 反射操作注解 一、 注解 1.简介 Annotation是JDK5.0开始引入…

day52|动态规划13-子序列问题

子序列系列问题 300.最长递增子序列 什么是递增子序列&#xff1a; 元素之间可以不连续&#xff0c;但是需要保证他们所在位置是元素在数组中的原始位置。 dp数组dp[i]表示以nums[i]为结尾的最长递增子序列的长度。递归函数&#xff1a;dp[i] max(dp[j]1,dp[j])初始化条件&…

Linux常用命令——gpm命令

在线Linux命令查询工具 gpm 提供文字模式下的滑鼠事件处理 补充说明 gpm命令是Linux的虚拟控制台下的鼠标服务器&#xff0c;用于在虚拟控制台下实现鼠标复制和粘贴文本的功能。 语法 gpm(选项)选项 -a&#xff1a;设置加速值&#xff1b; -b&#xff1a;设置波特率&…

chatgpt赋能python:Python中如何取出字符串中的数字并赋予新的变量

Python 中如何取出字符串中的数字并赋予新的变量 在 Python 中&#xff0c;我们经常需要处理字符串&#xff0c;其中可能包含多种类型的数据。当我们需要获取字符串中的数字时&#xff0c;该怎样做呢&#xff1f;本文将介绍取出字符串中的数字的方法&#xff0c;并赋予新的变量…

chatgpt赋能python:Python利器之数字提取

Python 利器之数字提取 Python 是一门强大的编程语言&#xff0c;被广泛应用在数据分析、人工智能等领域。在很多数据分析的场景下&#xff0c;需要从文本中提取数字&#xff0c;本文将介绍如何使用 Python 快速提取文本中的所有数字。 使用正则表达式提取数字 正则表达式&a…

YOLOv7 模型融合

将两种训练模型的检测结果融合 首先需要两种模型&#xff0c;一个是yolov7原有的模型&#xff0c;另一个是你训练出来的模型 其中yolov7.pt是官方提供的模型&#xff0c;有80个类别 其中yolov7_3.7HRW.pt是我们自己训练的模型&#xff0c;有三个分类&#xff0c;举手、看书、写…

WPF开发txt阅读器6:用树形图管理书籍

txt阅读器系列&#xff1a; 需求分析和文件读写目录提取类&#x1f48e;列表控件与目录字体控件绑定书籍管理系统 TreeView控件 TreeView可以通过可折叠的节点来显示层次结构中的信息&#xff0c;是表达文件系统从属关系的不二选择&#xff0c;其最终效果如下 为了构建这个树…

UnityVR--组件6--Animation动画

目录 新建动画Animation Animation组件解释 应用举例1&#xff1a;制作动画片段 应用举例2&#xff1a;添加动画事件 Animator动画控制器 应用举例3&#xff1a;在Animator中设置动画片段间的跳转 本篇使用的API&#xff1a;Animation、Animator以及Animator类中的SetFlo…

【Python可视化大屏】「淄博烧烤」热评舆情分析大屏

文章目录 一、开发背景二、爬虫代码2.1 展示爬取结果2.3 导入MySQL数据库 三、可视化代码3.1 大标题3.2 词云图&#xff08;含&#xff1a;加载停用词&#xff09;3.3 玫瑰图&#xff08;含&#xff1a;snownlp情感分析&#xff09;3.4 柱形图-TOP10关键词3.5 折线图-讨论热度趋…

ViewOverlay-使用简单实践

ViewOverlay-使用简单实践 一、ViewOverlay能实现什么&#xff1f;二、基础用法2.1 一个简单案例2.2 overlay.add(drawable)/groupOverlay.add(view)之后&#xff0c;不显示问题解决2.2.1 add(Drawable)方法2.2.1 add(View)方法 一、ViewOverlay能实现什么&#xff1f; 在Andro…

北京软件外包开发流程

随着软件的规模越做越多&#xff0c;功能也越来越复杂&#xff0c;对项目管理和开发人员也提出了更高的要求。软件开发的流程通常包括需求分析、项目评估与计划、设计、编码、测试等多个环节&#xff0c;今天和大家分享这方面的知识&#xff0c;希望对大家有所帮助。 软件外包开…

关系代数表达式练习(针对难题)

教师关系T&#xff08;T#,TNAME,TITLE&#xff09;课程关系C(C#,CNAME,TNO)学生关系S(S#,SNAME,AGE,SEX)选课关系SC(S#,C#,SCORE) 检索至少选修了C2,C4两门课程的学生学号&#xff1a; 涉及减法相关&#xff1a; 检索不学C2课的学生姓名和年龄 涉及除法相关&#xff1a; 检索…

使用SQL语句创建存储过程

前言: 本篇文章是记录学校学习SQL server中知识,可用于复习资料. 目录 前言:一、存储过程的创建1、创建简单存储过程2、创建带参数的存储过程3、创建带输出参数的存储过程 二 、使用T一SQL语句管理和维护存储过程2.1 使用sp_helptext查看存储过程student_sc的定义脚本2.2 使用…

Redis安装与启动

概念 简介&#xff1a;Redis是基于内存的数据结构存储系统&#xff0c;它可以用作:数据库、缓存和消息中间件。特点&#xff1a;Redis是用C语言开发的一个开源的高性能健值对(key-value)数据库&#xff0c;官方提供的数据是每秒内查询次数十万加。它存储的value类型比较丰富&a…

问麻了…阿里一面索命27问,过了就60W+

前言 在40岁老架构师尼恩的&#xff08;50&#xff09;读者社区中&#xff0c;经常有小伙伴&#xff0c;需要面试阿里、 百度、头条、美团、京东等大厂。 下面是一个小伙伴成功拿到通过了阿里三次技术面试&#xff0c;小伙伴通过三个多小时技术拷问&#xff0c;最终拿到 offe…

git修改commit的注释内容

文章目录 1. 查看所有commit2. 修改最近一次commit注释3. 修改某一次commit注释 要修改 Git 中的 commit 注释内容&#xff0c;可以使用 git commit --amend 命令。具体步骤如下&#xff1a; 1. 查看所有commit 运行 git log --oneline 命令&#xff0c;查看需要修改的 commi…