进程程序替换

news2025/2/6 4:15:14

文章目录

  • 进程程序替换是什么
    • 概念
    • 原理
  • 为什么要进行程序替换
  • 如何进行程序替换
  • 使用接口
    • execl
  • 引入进程创建
    • execv
    • execlp
    • execvp
    • execle


进程程序替换是什么

概念

通过之前的学习,我们知道子进程执行的是父进程的代码片段。
如果我们想让创建出来的子进程,执行的是全新的程序呢?
这里我们就需要用到进程程序替换。

原理

1.将磁盘中的程序,加载入内存结构
2.重新建立页表映射,谁执行程序替换,就重新建立谁的映射(子进程)
效果:让我们的父进程和子进程彻底分离,并让子进程执行一个新的程序。

在这里插入图片描述

那么问题来了!!!

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

答:我们肯定没有创建新的进程,只不过让子进程执行了新的程序


为什么要进行程序替换

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

  • 1.让子进程执行父进程的代码片段(服务器代码)
  • 2.让子进程执行磁盘中的一个全新的程序(shell,想让客户端执行对应的程序,通过我们的进程,执行其他人写的进程的代码等等)
    例如我们用C语言的进程去掉java/python/C++等等的程序。

如何进行程序替换

由OS完成,所以我们要调用系统接口。

首先带大家来看看系统接口有什么!

在这里插入图片描述
我们如果要执行一个全新的程序,我们需要做几件事情呢?

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

使用接口

execl

在这里插入图片描述

其中参数列表中:“…” 叫做可变参数,说白了就是可以按照用户的意愿传入参数的大小个数,如果还不理解,大家肯定都用过C语言中的printf函数吧,printf有没有规定你只能打印几个参数呢?没有的,这是根据用户自己来定义的!这就是可变参数

在这里插入图片描述

执行完以上的代码,我们发现一个问题!!!

最后一句代码为什么没有被打印出来呢???
因为进程一旦替换成功,是将当前进程的代码和数据全部替换了!!!

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

所以这个程序替换函数,用不用判断返回值?为什么?
答:不用判断返回值,因为只要成功了,就不会有返回值。而失败的时候,必然会继续向后执行!!最多通过返回值得到什么原因导致的替换失败!

引入进程创建

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<sys/types.h>

int main()
{
    printf("我是一个进程: %d\n",getpid());
    pid_t id=fork();
    if(id==0)
    {
        printf("我是子进程,我的pid是:%d\n",getpid());
        execl("/usr/bin/ls","ls","-l","-a",NULL);
        exit(1);
    }

    int status=0;
    pid_t ret=waitpid(id,&status,0);
    if(ret==id)
    {
        sleep(2);                 
        printf("父进程等待成功!\n");
    }
    
    return 0;
}

在这里插入图片描述

子进程进行程序替换的时候会不会影响父进程呢?
答:不会,因为进程具有独立性。

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

execv

他的第二个参数是一个指针数组,他和execl的区别就是把选项作为参数放入指针数组,然后进行传参!

int main()
  7 {
  8     printf("我是一个进程,我的pid是:%d\n",getpid());
  9     pid_t id=fork(); 
 10     if(id==0)
 11     {
 12         //child
 13         //我们想让子进程执行新的程序,以前是执行父进程的代码片段
 14         printf("我是子进程,我的pid是:%d\n",getpid());
 15       char *const argv_[]={
 16         (char*)"ls",
 17         (char*)"-a",
 18         (char*)"-l",
 19          NULL
 20          };
 21       execv("/usr/bin/ls",argv_);                                                                                                            
 22         exit(1);
 23     }
 24     //一定是父进程
 25     int status=0;
 26     int ret=waitpid(id,&status,0);
 27     if(ret==id)
 28     {
 29         sleep(2);
 30         printf("父进程等待成功!\n");
 31     }
 32 
 33     return 0;
 34 }

在这里插入图片描述
区分execl和execv
在这里插入图片描述

execlp

在这里插入图片描述

相比于execl这个接口的第一个参数变化。
我们执行指令的时候,默认的搜索路径,在哪里搜索呢?
环境变量PATH!

p代表PATH

所以命名中带p的,可以不带路径,只要说出你要执行哪一个程序即可!

#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());
      char *const argv_[]={
        (char*)"ls",
        (char*)"-a",
        (char*)"-l",
         NULL
         };
      	execlp("ls","ls","-a","-l",NULL);//这里出现了两个ls,含义一样吗?不一样!
        exit(1);
    }
    //一定是父进程
    int status=0;
    int ret=waitpid(id,&status,0);
    if(ret==id)
    {
        sleep(2);
        printf("父进程等待成功!\n");
    }

    return 0;
}


在这里插入图片描述

execvp

在这里插入图片描述

#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    printf("我是一个进程,我的pid是:%d\n", getpid());
    pid_t id = fork();
    if (id == 0)
    {
        // child
        // 我们想让子进程执行新的程序,以前是执行父进程的代码片段
        printf("execvp 我是子进程,我的pid是:%d\n", getpid());
       char *const argv_[] = {
            (char *)"ls",
            (char *)"-a",
            (char *)"-l",
            NULL};
        execvp("ls", argv_);
        exit(1);
    }
    // 一定是父进程
    int status = 0;
    int ret = waitpid(id, &status, 0);
    if (ret == id)
    {
        sleep(2);
        printf("父进程等待成功!\n");
    }

    return 0;
}

在这里插入图片描述

execle

在这里插入图片描述
这里的前两个接口都非常熟悉了,这里最后一个接口叫做环境变量。那么为什么要有这个接口呢?

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

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

#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    printf("我是一个进程,我的pid是:%d\n", getpid());
    pid_t id = fork();
    if (id == 0)
    {
        // child
        // 我们想让子进程执行新的程序,以前是执行父进程的代码片段
        printf("execl 运行mycmd 我是子进程,我的pid是:%d\n", getpid());
      /*char *const argv_[] = {
            (char *)"ls",
            (char *)"-a",
            (char *)"-l",
            NULL};*/
        execl("/home/jys/code.c/mycmd", "mycmd",NULL);
        exit(1);
    }
    // 一定是父进程
    int status = 0;
    int ret = waitpid(id, &status, 0);
    if (ret == id)
    {
        sleep(2);
        printf("父进程等待成功!\n");
    }

    return 0;
}

mycmd.cc

#include <iostream>
using namespace std;
int main()
{
    cout << "你调用了我,很好,你成功引起了我的注意" << endl;
    cout << "你调用了我,很好,你成功引起了我的注意" << endl;
    cout << "你调用了我,很好,你成功引起了我的注意" << endl;
    cout << "你调用了我,很好,你成功引起了我的注意" << endl;
    cout << "你调用了我,很好,你成功引起了我的注意" << endl;
    cout << "你调用了我,很好,你成功引起了我的注意" << endl;

    return 0;
}

在这里插入图片描述
我们当前使用的是绝对路径来吊用我的mycmd程序!
当然我们也可以使用相对路径来调用。

所以我们使用ece系列的系统级函数可以把任何语言耦合在一起!

谈完这个话题我们再来谈谈环境变量,execle这个函数多了一个e,这个e就是环境变量,如果你想给这个函数传入环境变量,我们就可以传入环境变量。
在这里插入图片描述
myexec.c

#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    extern char** __environ;
    printf("我是一个进程,我的pid是:%d\n", getpid());
    pid_t id = fork();
    if (id == 0)
    {

        // child
        // 我们想让子进程执行新的程序,以前是执行父进程的代码片段
        printf("execle 运行mycmd 我是子进程,我的pid是:%d\n", getpid());
        execle("/home/jys/code.c/mycmd", "mycmd",NULL,__environ);
        exit(1);
    }
    // 一定是父进程
    int status = 0;
    int ret = waitpid(id, &status, 0);
    if (ret == id)
    {
        sleep(2);
        printf("父进程等待成功!\n");
    }

    return 0;
}

mycmd.cc

#include <iostream>
#include<cstdlib>
using namespace std;
int main()
{
    cout<<getenv("USER")<<"\n";
    cout << "你调用了我,很好,你成功引起了我的注意" << endl;
    cout << "你调用了我,很好,你成功引起了我的注意" << endl;
    cout << "你调用了我,很好,你成功引起了我的注意" << endl;
    cout << "你调用了我,很好,你成功引起了我的注意" << endl;
    cout << "你调用了我,很好,你成功引起了我的注意" << endl;
    cout << "你调用了我,很好,你成功引起了我的注意" << endl;

    return 0;
}

在这里插入图片描述
这个是父进程用extern继承了系统的环境变量,子进程继承了父进程的环境变量


#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
   // extern char** __environ;
    printf("我是一个进程,我的pid是:%d\n", getpid());
    pid_t id = fork();
    if (id == 0)
    {

        // child
        // 我们想让子进程执行新的程序,以前是执行父进程的代码片段
        printf("execle 运行mycmd 我是子进程,我的pid是:%d\n", getpid());
      /*char *const argv_[] = {
            (char *)"ls",
            (char *)"-a",
            (char *)"-l",
            NULL};*/
         char* const env_[]={(char*)"MYPATH=迪丽热巴我老婆\n",NULL};
        execle("./mycmd", "mycmd",NULL,env_);
        exit(1);
    }
    // 一定是父进程
    int status = 0;
    int ret = waitpid(id, &status, 0);
    if (ret == id)
    {
        sleep(2);
        printf("父进程等待成功!\n");
    }

    return 0;
}

在这里插入图片描述

#include <iostream>
#include<cstdlib>
using namespace std;
int main()
{
    cout<<getenv("MYPATH")<<"\n";
   // cout<<getenv("USER")<<"\n";
    
    cout << "你调用了我,很好,你成功引起了我的注意" << endl;
    cout << "你调用了我,很好,你成功引起了我的注意" << endl;
    cout << "你调用了我,很好,你成功引起了我的注意" << endl;
    cout << "你调用了我,很好,你成功引起了我的注意" << endl;
    cout << "你调用了我,很好,你成功引起了我的注意" << endl;
    cout << "你调用了我,很好,你成功引起了我的注意" << endl;

    return 0;
}

在这里插入图片描述

这里我们发现我们导入的环境变量出现了!

我们很好奇为什么呢?依照上面两个实验我们可以得出什么结论呢?

我们可以得出execle添加环境变量给目标程序的时候是覆盖式传入的!!

我们自己传入系统的环境变量给我们程序替换的程序


#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
   extern char** __environ;
    printf("我是一个进程,我的pid是:%d\n", getpid());
    pid_t id = fork();
    if (id == 0)
    {

        // child
        // 我们想让子进程执行新的程序,以前是执行父进程的代码片段
        printf("execle 运行mycmd 我是子进程,我的pid是:%d\n", getpid());
      /*char *const argv_[] = {
            (char *)"ls",
            (char *)"-a",
            (char *)"-l",
            NULL};*/
         //char* const env_[]={(char*)"MYPATH=迪丽热巴我老婆\n",NULL};
        execle("./mycmd", "mycmd",NULL,__environ);
        exit(1);
    }
    // 一定是父进程
    int status = 0;
    int ret = waitpid(id, &status, 0);
    if (ret == id)
    {
        sleep(2);
        printf("父进程等待成功!\n");
    }

    return 0;
}

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

PPT丑哭了?这个工具做报表上手更简单,效果更酷炫,送40套模板

如果2023年你还做着万年不变的饼图、折线图&#xff0c;你将会再次错失涨薪的机会&#xff01; 数据有多重要&#xff0c;已经不言而喻&#xff0c;随之而来的是职场对数据分析与展示能力的要求也越来越高。 但是你是不是这种情况&#xff1f;一用图表就只会用饼图、折线图&a…

ice.js 3 的体验优化策略介绍

ice.js 3 已经正式发布&#xff0c;期待更多的业务来使用、验证&#xff0c;一起建设更好的用户体验。ice.js 3 地址&#xff1a;https://v3.ice.work/本文将简单介绍 ice.js 3 中已经落地和正在进行的一些体验优化策略&#xff0c;以供探讨。Chrome 在去年成立了一个名为 Auro…

Allegro如何导出光绘和颜色设置到其它单板上操作指导

Allegro如何导出光绘和颜色设置到其它单板上操作指导 Allegro有个非常强大的功能,支持把光绘设置和颜色设置等等参数从一个PCB导入到另外一块PCB中,如下图 具体操作如下 导出参数设置,file-export选择Parameters

优优绿能冲刺创业板:年营收4.3亿估值25亿 小米是股东

雷递网 雷建平 12月19日深圳市优优绿能股份有限公司&#xff08;简称&#xff1a;“优优绿能”&#xff09;日前递交招股书&#xff0c;准备在深交所创业板上市。优优绿能计划募资7亿元&#xff0c;其中&#xff0c;2.7亿元用于深圳市优优绿能股份有限公司充电模块生产基地建设…

[附源码]计算机毕业设计Python二次元信息分享平台的设计及实现(程序+源码+LW文档)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等…

数商云采购管理系统支付结算功能详解,实现建筑工程企业采购业务智能化管理

建筑工程行业企业过去受技术、场地等限制&#xff0c;一直采用传统的采购方式&#xff0c;再加上整个行业内部信息相对割裂、采购面临层层传播、中间沟通亦面临多层税费等问题&#xff0c;为建筑工程采购工作增添了不少困难。随着互联网时代的发展&#xff0c;在大数据、云计算…

云原生之使用Docker部署Dashdot服务器仪表盘

云原生之使用Docker部署Dashdot服务器仪表盘一、Dashdot介绍二、检查本地系统环境1.检查本地系统版本2.检查docker状态3.检查docker版本三、下载Dashdot镜像四、部署Dashdot应用1.创建安装目录2.创建Dashdot容器3.查看Dashdot容器状态五、访问Dashdot一、Dashdot介绍 Dashdot是…

未来十年,Python将如何发展?

随着人工智能的发展和普及&#xff0c;作为人工智能首选语言的Python&#xff0c;也越来越受到大家的欢迎。可能也有很多同学想知道未来十年&#xff0c;Python会有什么样的发展。如果发展得非常好&#xff0c;就值得我们亲自去机构进行考察试学&#xff0c;值得我们花时间、花…

克隆一个虚拟机

文章目录1、打开虚拟机2、选择要克隆的虚拟机3、选择当前状态4、创建完整克隆&#xff08;链接克隆会导致本体和克隆体在一些资源上是公用的&#xff0c;不太合适&#xff09;5、重命名克隆虚拟机的名字&#xff0c;并且更改克隆的虚拟机所在位置7、登录这个虚拟机8、因为两个虚…

[附源码]计算机毕业设计Python防疫物资捐赠(程序+源码+LW文档)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

[附源码]计算机毕业设计Node.jswai音乐网站(程序+LW)

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

Docker-Nacos的持久化和集群部署

目录 一&#xff0c;准备工作 1.1 修改虚拟机内存大小 二&#xff0c;docker mysql:5.7的持久化存储及远程连接 1.1 下载相关镜像 1.2 在宿主机中相关目录&#xff0c;用于挂载容器的相关数据 1.3.创建mysql5.7容器 1.4.修改mysql允许Navicat远程连接 1.5 创建数据库nacos_…

实用指南:手把手搭建坚若磐石的DevSecOps框架

长期以来&#xff0c;安全问题一直被当作软件开发流程中的最后一步。开发者贡献可以实现软件特性的代码&#xff0c;但只在开发生命周期的测试和部署阶段考虑安全问题。随着盗版、恶意软件及网络犯罪事件飙升&#xff0c;开发流程需要做出改变。 开发过程中的“安全左移”是…

基于java的fofa爬虫

文章目录下载链接介绍使用方法关键字生成器API爬虫Fofa爬虫导出功能修改配置文件下载链接 github : https://github.com/13337356453/FofaSpidercsdn : https://download.csdn.net/download/realmels/87320066 介绍 顾名思义&#xff0c;fofa爬虫。可以用api爬&#xff0c;也…

leetcode:1192. 查找集群内的关键连接【tarjan模版 + 找割边】

目录题目截图题目分析割边割点强连通子图ac codetarjan模版总结题目截图 题目分析 找割边 割边 割点 强连通子图 我觉得就是割边左右的两个子图&#xff1f;应该是去掉n条割边后&#xff0c;剩下n 1个强连通子图的意思吧。。。 ac code class Solution:def criticalConne…

【愚公系列】2022年12月 .NET CORE工具案例-多语言离线翻译系统

文章目录前言1.在线翻译2.离线翻译一、多语言离线翻译系统1.开发环境2.准备离线翻译包3.准备python代码4.调试翻译结果5.Python翻译服务对接到.NET Core前言 1.在线翻译 在线翻译&#xff0c;一般是指在线翻译工具&#xff0c;如百度翻译、阿里翻译1688或Google翻译等。这类翻…

计算机毕业设计django基于python的在线教育平台

项目介绍 随着科学技术的飞速发展,社会的方方面面、各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,在线教育平台当然也不能排除在外。在线教育平台是以实际运用为开发背景,运用软件工程原理和开发方法,采用django框架构建的一个管理系统。整个开发过程首…

fpga实操训练(小功能到模块开发)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 有过c、java编程语言经验的朋友&#xff0c;是否还记得曾经自己是如何学习编程语言的&#xff1f;一开始的时候&#xff0c;为了学习语法&#xff…

光电传感器调研报告

目录 前言&#xff1a; 一、理论基础——光电效应 二、光电传感器原理 三、光电元件 3.1光电管 3.2光敏电阻 四、光电传感器特性 4.1伏安特性 4.2光电特性 4.3光谱特性 五、光电传感器的应用 LED&#xff08;发光二极管&#xff09; 超声波传感器 光纤 六、总结 …

用Python赚钱的方法有哪些?

很多人想知道用Python赚钱的方法有哪些&#xff1f;Python很容易使用&#xff0c;应用性较强。可以通过使用Python开发小程序、抓取数据、游戏开发、兼职编程老师&#xff0c;发展副业的方式来赚钱。 用Python赚钱的方法&#xff1a; 1、某宝搜python程序   可以到某宝上搜&a…