进程控制(三):进程替换

文章目录

  • 进程控制(三)
  • 进程替换
    • 进程替换函数
    • 进程中的环境变量
  • 总结


进程控制(三)

进程控制中的进程替换,下文我们学习进程替换的意义,以及进程替换的方式

进程替换

初步认识进程替换,我们先使用一个比较简单的execl函数,来实现进程替换,并从结果上,了解替换的原理。

单进程进程替换

简单实现一下进程替换,以此推理进程替换原理

在这里插入图片描述

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>


int main()
{
  //实现单进程的进程替换
  printf("hello linux\n");//输出
  execl("/usr/bin/ls","ls","-a","-l",NULL);//输入的第一个参数为要执行的进程的绝对路径,后面的参数为命令行参数,可变序列参数以NULL结尾,表示结束
  
  printf("hello world\n");
  return 0;
}

单进程实现进程替换,我们发现进程的代码和数据会被替换,替换execl函数内参数所指定的内容。

多进程(父子进程)实现进程替换

在这里插入图片描述

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

int main()
{
  //实现单进程的进程替换
 // printf("hello linux\n");//输出
 // execl("/usr/bin/ls","ls","-a","-l",NULL);//输入的第一个参数为要执行的进程的绝对路径,后面的参数为命令行参数,可变序列参数以NULL结尾,表示结束
 // 
 // printf("hello world\n");
  
  //实现多进程(父子进程)进程替换
  
  //创建子进程
  pid_t id=fork();

  if(id==0)
  {
    //表示子进程
    printf("i am child process pid: %d ppid: %d\n",getpid(),getppid());//得到父进程子进程的pid
    execl("/usr/bin/ls","ls","-l",NULL);//实现程序替换

    exit(11);//退出码,查看是否是会覆盖该代码,如果覆盖的话,我们执行的是ls命令,执行成功,返回码exit为0,通过waitpid进行等到得到status,WEXITSTATUS(status)来判断是否是这样
  }
  else if(id<0)
  {
    //表示子进程创建失败
    perror("fork failed\n");
    exit(1);//表示是创建失败
  }
  else 
  {
    //这是父进程要执行的内容,我们先进行等待
    
    //waitpid等待
    int status=0;
    pid_t ret=waitpid(-1,&status,0);//阻塞等待

    if(ret<0)
    {
      //表示等待失败
      perror("wait failed\n");
      exit(2);
    }
    else 
    {
      //等待成功,我们要输出的是子进程的退出码
      printf("i am parent pid: %d child pid: %d child exit_code: %d\n",getpid(),id,WEXITSTATUS(status));
    }
  }
    return 0;
}

上述多进程进程替换后的结果,表明了进程替换的原理,为将新进程的数据和代码直接覆盖原来的进程的代码。

进程替换原理

  1. 首先,我们知道进程运行时,有task_struct结构体来存储进程信息,以及虚拟空间地址(mm_struct)存储数据,通过页表映射到物理内存
  2. 先运行原有进程,然后fork创建子进程,在子进程中使用进程替换,把子进程的数据和代码进行替换,操作系统识别到要更改子进程的代码和数据,在物理内存中开辟空间,将新进程代码和数据放入,更改页表指向该地址。
  3. 通过上述步骤,实现了子进程的进程替换,此时子进程的task_struct除了代码和数据地址,其他没有变化。

如下图所示:

在这里插入图片描述

通过上述内容,我们就能明白进程替换的原理了,起始就是更改物理空间原有进程的代码数据,如果是父子进程,那么就在物理空间上开辟新空间,存放代码和数据,更改子进程页表指向。

进程替换函数

进程替换函数有7种,其中,库函数(man 3号手册)中有6种函数,系统调用(man 2号手册)有一种函数

在这里插入图片描述

       //man 2 exec   库函数 6种
	   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[]);

下面是这6种函数的使用样例:

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


int main()
{
  //使用进程替换,为了简单的演示,我们就单纯使用单进程进程替换来实现
  //1. int execl(const char *path, const char *arg, ...);
  int num=0;
  scanf("%d",&num);//输入参数选定不同的进程替换参数
  if(num==1)
  {
    printf("进程替换函数execl\n");
    execl("/usr/bin/ls","ls","-l",NULL);//实现完毕,可变列表的实现,以NULL为结尾
    printf("进程替换完毕\n");
  }
  else if(num==2)
  {
    //int execlp(const char *file, const char *arg, ...);
    //该函数的实现,第一个参数,不必要使用绝对路径,会从PATH以及当前目录下,找到可执行文件,并结合avg命令行参数实现
    printf("execlp函数的实现\n");
    execl("/usr/bin/pwd","pwd",NULL);//实现显示当前工作路径
  }
  else if(num==3)
  {
    //int execle(const char *path, const char *arg,  ..., char * const envp[]);
    //实现功能:需要绝对路径,需要可变列表,需要环境变量
    printf("execle函数的实现\n");
    char * const env[]={"why=123",NULL};
    execle("/usr/bin/ls","ls",NULL,env);
  }
  else if(num==4)
  {
    // int execv(const char *path, char *const argv[]);
    printf("execv函数的实现\n");
    char * const argv[]={"top",NULL};
    execv("/usr/bin/top",argv);

  }
  else if(num==5)
  {
    //int execvp(const char *file, char *const argv[]);
    printf("execvp函数的实现\n");
    char * const argv[]={"ls",NULL};
    execvp("ls",argv);
  }
  else if(num==6)
  {
    //int execvpe(const char *file, char *const argv[],  char *const envp[]);
    printf("execvpe函数的实现\n");
    char * const argv[]={"ls",NULL};
    char * const env[]={"lll=123456",NULL}; 
    execvpe("/usr/bin/ls",argv,env);
  }
  return 0;
}

解释:

  1. 对于环境变量以及命令函参数,无论是可变参数形式,还是字符指针数组形式,最后一个元素都要是NULL结尾,标志参数输入完毕。
  2. 对于这六种函数本质上没什么太大的区别,只是对于参数的形式不同。
  3. 关于环境变量,我们可以使用putenv和getenv函数来增加或者得到指定的环境变量,参数都是字符指针类型,比如getenv(“PATH”)

进程中的环境变量

对于进程中的环境变量进行解释,以下图为准

在这里插入图片描述

  1. getenv和putenv函数可以实现得到/创建环境变量信息
  2. PATH环境变量,父子进程都能获得,我们在后文可知,实际上是bash对于进程默认传参environ环境变量(在Linux下就是env命令展示的内容),所以只要系统环境变量中存在的,我们在进程中都能直接getenv获得。
  3. 子进程得到环境变量有两种方式:新增环境变量(putenv,在fork之前),另外是通过进程替换函数,自定义环境变量参数,传参(是彻底替换,即覆盖默认environ)

在这里插入图片描述

通过上述图中代码结果表明,我们putenv新建的环境变量,实际上只是在当前进程中的environ有效,但是等进程结束之后,输入env命令,并不会有我们新增的环境变量,这说明,由于进程的独立性,子进程的环境变量并不会影响其他进程(系统,本身也是一个进程)。

在这里插入图片描述

最后,对于库函数中的6种进程替换函数,以及对于其中环境变量与进程的关系,我们已经解释完毕,最后一个系统函数调用execve,我们只需要知道,前6种库函数,最后底层都是调用该函数,对于操作系统进行操作(也只有系统调用函数才能对于操作系统操作),以此全局视角,才能操控进程,从而替换进程中数据和代码,最终实现进程替换。

总结

  • 进程替换,实际上只是对于该进程的程序和代码进行替换,子进程的其他信息如pid等都不发生变化,如果是存在父子进程的情况,对父子进程进程替换,会在物理空间中在开辟新空间来存放新进程的代码和数据。
  • 掌握7个进程替换函数,其中6个是库函数,一个是系统调用函数,库函数的底层会使用这个系统调用函数,来实现对于系统中的进程进行操作。
  • 进程环境变量是有默认的数值的,即一个进程默认的环境变量为操作系统中的env命令展示的内容,在C语言中,我们将environ(类型为char**)变量指向该环境变量,如果在执行进程替换中传递我们自己创建的环境变量, 如myenv,会覆盖原有的environ环境变量。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring Cloud应用- Eureka原理、搭建

初期对Spring Cloud的学习以应用搭建为主&#xff0c;所以内容不会太枯燥。 一直以来&#xff0c;自以为Spring全家桶的学习中&#xff0c;Spring framework是基础中的基础&#xff0c;部分内容也还是必须要读源码去理解底层原理&#xff0c;SpringMVC、SpringBoot&#xff0c…

【ElasticSearch系列-03】ElasticSearch的高级句法查询Query DSL

ElasticSearch系列整体栏目 内容链接地址【一】ElasticSearch下载和安装https://zhenghuisheng.blog.csdn.net/article/details/129260827【二】ElasticSearch概念和基本操作https://blog.csdn.net/zhenghuishengq/article/details/134121631【二】ElasticSearch的高级查询Quer…

Linux上编译sqlite3库出现undefined reference to `sqlite3_column_table_name‘

作者&#xff1a;朱金灿 来源&#xff1a;clever101的专栏 为什么大多数人学不会人工智能编程&#xff1f;>>> 在Ubuntu 18上编译sqlite3库后在运行程序时出现undefined reference to sqlite3_column_table_name’的错误。网上的说法是说缺少SQLITE_ENABLE_COLUMN_M…

解决ModuleNotFoundError: No module named ‘yaml‘

报错&#xff1a;ModuleNotFoundError: No module named yaml 使用&#xff1a; pip install yaml 仍然报错&#xff1a; 最终解决方案&#xff1a; pip install pyyaml 或者 conda install pyyaml

百度竞价排名推广对比自然排名哪一个更具优势-华媒舍

在搜索引擎结论网页页面&#xff08;SERP&#xff09;中&#xff0c;我们经常会看到一些网站链接及其广告栏。这种连接一般分为两种类型&#xff1a;百度竞价推广排名推广与自然排名。究竟哪个更有优势&#xff1f;本文将对这几种排名形式进行科谱详细介绍。 什么叫百度竞价推广…

右击显示Pycharm打开教程

效果图 操作流程 win r 输入 regedit 回车打开注册表编辑器 2.找到 shell 路径 计算机\HKEY_CLASSES_ROOT\Directory\shell3.在 shell 下新建项&#xff0c;名称为 Pycharm 单击Pycharm文件夹&#xff0c;双击默认项&#xff0c;修改默认值&#xff0c;这个数值就是你右击后…

KaiwuDB 内核解析 - SQL 查询的生命周期

一、概述 KaiwuDB 内核解析系列共分上下两部分&#xff0c;本文是该系列的第一部分&#xff0c;主要涵盖了网络协议到 SQL 执行器&#xff0c;解释 KaiwuDB 如何执行 SQL 查询&#xff0c;包括系统各个组件的执行路径&#xff08;网络协议、SQL 会话管理、解析器、执行计划及优…

ucos_conf、ucos_src和ucos_port

目录 ucos_conf 文件夹ucos_src 文件夹ucos_port 文件夹 在 uC/OS-II 中&#xff0c;ucos_conf、ucos_src 和 ucos_port 是三个不同的文件夹&#xff0c;它们的作用和功能有所不同&#xff1a; ucos_conf 文件夹 ucos_conf 文件夹&#xff1a;ucos_conf 文件夹包含了 uC/OS-II…

CSGO游戏里的饰品是如何被炒作起来的?

csgo倒狗们是如何操盘csgo饰品市场的&#xff1f; CSGO游戏里的饰品是如何被炒作起来的&#xff1f; 随着近几年csgo玩家数量急剧上升&#xff0c;倒狗在市场中的比例也在上升&#xff0c;之前的csgo饰品市场以散户居多&#xff0c;价格波动不大&#xff0c;现在倒狗大量涌入&a…

Docker学习——①

文章目录 1、什么是虚拟化、容器化&#xff1f;2、为什么要虚拟化、容器化&#xff1f;3、虚拟化实现方式3.1 应用程序执行环境分层3.2 虚拟化常见类别3.3 常见虚拟化实现3.3.1 主机虚拟化(虚拟机)实现3.3.2 容器虚拟化实现3.3.3 空间隔离实战--基础知识3.3.4 PID 隔离3.3.5 Mo…

【优选算法系列】【专题九链表】第一节.链表常用技巧和操作总结(2. 两数相加)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、链表常用技巧和操作总结二、两数相加 2.1 题目描述 2.2 题目解析 2.2.1 算法原理 2.2.2 代码编写总结 前言 一、链表常…

uniapp自定义权限菜单,动态tabbar

已封装为组件&#xff0c;亲测4个菜单项目可以切换&#xff0c; 以下为示例&#xff0c;根据Storage 中 userType 的 值&#xff0c;判断权限菜单 <template><view class"tab-bar pb10"><view class"tabli" v-for"(tab, index) in ta…

会声会影2024对比2023变化以及功能对比

全新会声会影2024版本现已登场&#xff0c;小伙伴们相信已经急不可待地想知道2024版到底有哪些新功能。对比2023版本&#xff0c;会声会影2024版本有没有功能的增强&#xff1f;事不宜迟&#xff0c;现在就让我们一起来看看会声会影2024对比2023的变化&#xff0c;包括功能对比…

什么是Babel?它的主要作用是什么?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

编译正点原子LINUXB报错make: arm-linux-gnueabihf-gcc:命令未找到

编译正点原子LINUX报错make: arm-linux-gnueabihf-gcc&#xff1a;命令未找到 1.报错内容2.解决办法3./bin/sh: 1: lzop: not found4.编译成功 1.报错内容 make: arm-linux-gnueabihf-gcc&#xff1a;命令未找到CHK include/config/kernel.releaseCHK include/generat…

unity3d 开发笔记

unity 3d Unity是一个游戏引擎&#xff0c;包含渲染引擎&#xff0c;物理引擎&#xff0c;碰撞检测&#xff0c;音效&#xff0c;动画效果&#xff0c;场景管理等系统。它的开发效率高、脚本使用C#开发、简单易用、跨平台&#xff08;可以导出各个平台的程序&#xff09;&…

家庭用洗地机哪个最好?家用洗地机选购

家里日常打扫&#xff0c;维持地面的清洁&#xff0c;清洁干湿垃圾这时候必不可缺的就是洗地机了&#xff0c;由于近年来洗地机行业的热度高涨&#xff0c;涌现了很多洗地机品牌&#xff0c;这也让消费者在挑选的时候无从下手&#xff0c;今天笔者就给大家讲讲洗地机挑选需要主…

Linux 下C++工程编译

创建文件夹 #include<iostream> using namespace std;int main(){cout<<"THis is C program Process!"<<endl;}编译执行命令&#xff1a; g test.cpp -o test实际上&#xff0c;上述的命令包含了如下的四个过程&#xff1a; 1. 预处理 g -E …

东北大学python大作业

目前金属矿开采&#xff0c;爆破还是主要的破岩方式&#xff0c;为了保证巷道采场的安全&#xff0c;需要对爆破震动进行监测&#xff0c;获取的监测数据如附件&#xff0c;第1列数据为震动的序号&#xff0c;第2、3、4列为x,y,z三个方向的震动速度&#xff0c;往往由于各种因素…

【CSS】CSS基础知识扫盲

1、 什么是CSS&#xff1f; CSS即层叠样式表 (Cascading Style Sheets). CSS 能够对网页中元素位置的排版进行像素级精确控制, 实现美化页面的效果. 能够做到页面的样式和结构分离 2、 CSS引入方式 CSS代码编写的时候有多种引入方式&#xff1a; 内部样式、外部样式、内联样…