Linux:进程终止和进程替换

news2024/11/29 2:42:17

Linux:Linux:进程终止和进程替换

  • 一、进程终止
    • 1.1 进程退出场景和创建退出方式
  • 1.2 exit 和 _exit区别
  • 二、进程程序替换
    • 2.1 进程替换函数
    • 2.2 函数解释及命名解释
      • 函数解释
      • 命名解释
    • 2.3 单进程程序替换(无子进程)
      • 2.3.1 带`l`函数进程替换(execl为例)
      • 2.3.2 带`p‘函数进程替换(execlp为例)
      • 2.3.3 execv、execvp替换函数应用实例
    • 2.4 进程替换其他程序,调用运行其他语言程序
  • 三、进程替换时环境变量的继承
    • 3.1 进程替换时,子进程环境变量由来
      • 3.2 为何父子进程间环境变量的继承不受进程替换的影响
      • 3.3 子进程获取环境变量的3种方式

一、进程终止

1.1 进程退出场景和创建退出方式

 进程退出有3种场景:代码执行完毕,结果正确;代码执行完毕,结果错误;代码异常终止!

 而进程退出的常见方式主要分为以下两大类:

正常终止
从main返回
调用exit退出
调用_exit退出
异常终止ctrl c, 信号终止

1.2 exit 和 _exit区别

  exit 和 _exit都可以直接终止进程。但_exit是系统调用接口,而exit为函数调用,底层封装了exit。
不同的是,exit终止进程时,会刷新缓冲区,执行用户的清理函数,关闭流等操作;而_exit则是直接“粗暴”的退出进程,不做任何其他工作!!

在这里插入图片描述

二、进程程序替换

 fork()创建子进程时,子进程执行的代码和数据都是父进程的一部分。如果我们想让子进程执行全新的代码,访问全新的数据,我们可以采用一种技术 —— 程序替换!而进程替换可以将命令行参数和环境变量传递给被替换程序的main()函数参数!!

2.1 进程替换函数

 进程替换函数有6种以exec开头的函数,统称为exec函数。

 #include <unistd.h>

 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[]);

 而exec函数底层都封装了系统调用接口execve的疯转,以实现不同的需求!

 #include <unistd.h>

 int execve(const char *filename, char *const argv[], char *const envp[]);

2.2 函数解释及命名解释

函数解释

  1. 如果这些函数调用成功,也就意味着进程替换成功。此时重新加载新的程序,从启动代码开始执行,并且不再返回。即进程替换后,执行新程序,执行完后直接退出!!
  2. 如果进程替换函数执行失败,此时返回值设为-1。
  3. exec函数只有出错的返回值,没有成功的返回值。

命名解释

  • l(list):参数采用列表形式。
  • v(vector):参数采用数组。
  • p(path):带p表示执行程序时,OS会自带去环境变量PATH中查找路径。
  • e(env):表示自己维护环境变量。

2.3 单进程程序替换(无子进程)

2.3.1 带l函数进程替换(execl为例)

 下面我们在一段代码的开头和结尾分别输出打印相关信息,然后两段信息输出代码直接调用execl替换ls -a-l

【源代码】:

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


int main()
{
    printf("pid: %d, ecec command begin!\n", getpid());
    
    //进程替换,执行ls指令相关程序
    execl("/usr/bin/ls", "ls", "-a", "-l", NULL);
    
    printf("pid: %d, ecec command end!\n", getpid());

    return 0;
}

【运行结果】:

在这里插入图片描述

【函数参数原型解释】:


在这里插入图片描述



在这里插入图片描述


2.3.2 带`p‘函数进程替换(execlp为例)

【源代码】:(头文件省略)

int main()
{
    printf("pid: %d, ecec command begin!\n", getpid());
    execlp("pwd", "pwd", NULL);
    printf("pid: %d, ecec command end!\n", getpid());
    return 0;
}

【运行结果】:

在这里插入图片描述

【函数参数原型解释】:
在这里插入图片描述
在这里插入图片描述

2.3.3 execv、execvp替换函数应用实例

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


int main()
{
    char *const argv[] = {
        "ls",
        "-l",
        "-a",
        NULL
    };
    printf("pid: %d, ecec command begin!\n", getpid());// 和execl、execlv类似,只不过下面函数时通过指针数组的方式,指明替换程序的执行方式!!
    execv("/usr/bin/ls", argv);
    execvp("ls", argv);
    
    printf("pid: %d, ecec command end!\n", getpid());

    return 0;
}

2.4 进程替换其他程序,调用运行其他语言程序

 上述所有的程序替换都是替换系统指令程序,那如何替换自己写的程序。
 下面我们在c程序中创建子进程,让子进程发送进程替换一段c++可执行程序,并且父进程等待子进程!!

【待替换C++程序】:

#include <iostream>

int main()
{
	std::cout << "hello c++!" << std::endl;
    std::cout << "hello c++!" << std::endl;
    std::cout << "hello c++!" << std::endl;
    return 0;
}

【主代码C程序】:

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

extern char **environ;

int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        printf("pid: %d, ecec command begin!\n", getpid());
     	execl("./mytest", "mytest");//替换C++程序
     	//替换失败,执行下面代码
        printf("pid: %d, ecec command end!\n", getpid());
        exit(1);
    }
   
    pid_t rid = waitpid(-1, NULL, 0);
    if(rid == id)
    {
        printf("wait pid: %d success!!!\n", rid);
    }
    return 0;
}

【运行结果】:

在这里插入图片描述

  • 为啥在c程序中,可以直接替换c++程序?根本原因在于exec函数发生的是进程替换,任何语言程序一旦运行起来就变成了进程,便可发生进程替换。系统大于一切!!

三、进程替换时环境变量的继承

3.1 进程替换时,子进程环境变量由来

 环境变量是数据,所有可以通过地址空间实现父子间通过写时拷贝的方式共享数据 —— 环境变量。所以当通过exec函数进行进程替换时,子进程的环境变量是直接从父进程来的。

3.2 为何父子进程间环境变量的继承不受进程替换的影响

 父进程和子进程间通过写时拷贝的方式,让环境变量别子进程继承,从而实现环境变量的全局性!但为何调用exec函数进行进程替换后,环境变量没有发生修改,变为被替换程序的环境变量?

 原因很简单,程序替换,只替换新程序的代码和数据,环境变量不会被替换!!

3.3 子进程获取环境变量的3种方式

  1. 操作系统直接将环境变量传递给子进程,子进程直接用。或者直接通过execle、execvpe的最后一个参数直接传递给子进程!

【实例】:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
extern char **environ;

int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        execle("./mytest", "mytest", NULL, environ);//进程替换,直接将environ传递给子进程
        exit(1);
    }
   
    pid_t rid = waitpid(-1, NULL, 0);
    if(rid == id)
    {
        printf("wait pid: %d success!!!\n", rid);
    }
    return 0;
}
  1. 直接构造自己的环境变量表传递给子进程。

【实例】:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
extern char **environ;

int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        execle("./mytest", "mytest", NULL, environ);//进程替换,直接将environ传递给子进程
        exit(1);
    }
   
    pid_t rid = waitpid(-1, NULL, 0);
    if(rid == id)
    {
      	char *const envp[] = {
         	"MYENV1 = 111111111111111111",
        	"MYENV2 = 111111111111111111",
        	"MYENV3 = 111111111111111111",
       		 NULL
    	};
        execle("./mytest", "mytest", NULL, envp);//直接将自己构造的函数变量表envp传递给子进程
     }
    return 0;
}
  1. 借助putenv(),新增环境变量给父进程然后传递给子进程

【实例】:

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

extern char **environ;

int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        char *myenv = "MYENV = 111111111111111111";
        putenv(myenv);//将环境变量MYENV添加到父进程环境变量表中
        
        execl("./mytest", "mytest");//直接传递给子进程
        exit(1);
    }
   
    pid_t rid = waitpid(-1, NULL, 0);
    if(rid == id)
    {
        printf("wait pid: %d success!!!\n", rid);
    }
    return 0;
}

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

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

相关文章

Ubuntu配置GitHub(第一次clone/push)

文章目录 1. 安装Git&检查连接2. 注册GitHub3. 生成&GitHub添加SSH3.1. 检查&删除已有id_rsa3.2. 生成SSH3.3. GitHub添加id_rsa.pub SSH3.4. 检查SSH 4. 继续开发可以参考参考 1. 安装Git&检查连接 安装 sudo apt-get install git检查SSH连接 ssh -T gitgi…

C++——stack和queue类用法指南

一、stack的介绍和使用 1.1 stack的介绍 1、stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行插入与提取操作 2、stack是作为容器适配器被实现的&#xff0c;容器适配器即是对特定类封装作为其底层的容器&am…

clickhouse高可用可拓展部署

clickhouse高可用&可拓展部署 1.部署架构 1.1高可用架构 1.2硬件资源 部署服务 节点名称 节点ip 核数 内存 磁盘 zookeeper zk-01 / 4c 8G 100G zk-02 / 4c 8G 100G zk-03 / 4c 8G 100G clikehouse ck-01 / 32c 128G 2T ck-02 / 32c 128G 2T ck-03 / 32c 128G 2T ck-04 /…

设计模式之模版方法

模版方法介绍 模版方法&#xff08;Template Method&#xff09;模式是一种行为型设计模式&#xff0c;它定义了一个操作&#xff08;模板方法&#xff09;的基本组合与控制流程&#xff0c;将一些步骤&#xff08;抽象方法&#xff09;推迟到子类中&#xff0c;使得子类可以在…

LeetCode热题100刷题8:54. 螺旋矩阵、73. 矩阵置零、48. 旋转图像

54. 螺旋矩阵 class Solution { public:vector<int> spiralOrder(vector<vector<int>>& matrix) {vector<int> vec;if(matrix.empty())return vec;int left0;int right matrix[0].size()-1;int up0;int down matrix.size()-1;while(true) {for(i…

【TB作品】脉搏测量,ATMEGA8单片机,Proteus仿真,ATmega8控制脉搏测量与显示系统

硬件组成&#xff1a; LCD1602脉搏测量电路&#xff08;带灯&#xff09;蜂鸣器报警按键设置AT24C02 功能&#xff1a; &#xff08;1&#xff09;LCD1602主页显示脉搏、报警上限、报警下限&#xff1b; &#xff08;2&#xff09;五个按键&#xff1a;按键1&#xff1a;切换设…

axios的使用,处理请求和响应,axios拦截器

1、axios官网 https://www.axios-http.cn/docs/interceptors 2、安装 npm install axios 3、在onMouunted钩子函数中使用axios来发送请求&#xff0c;接受响应 4.出现的问题&#xff1a; &#xff08;1&#xff09; 但是如果发送请求请求时间过长&#xff0c;回出现请求待处…

RK3568 GPU介绍及使用

一、RK3568简介 RK3568四核64位Cortex-A55 处理器&#xff0c;采用全新ARM v8.2-A架构&#xff0c;主频最高可达2.0GHz&#xff0c;效能有大幅提升&#xff1b;采用22nm先进工艺&#xff0c;具有低功耗高性能的特点RK3568集成了双核心架构 GPU&#xff0c;高性能VPU以及高效能…

YOLOv8_obb数据集可视化[旋转目标检测实践篇]

先贴代码,周末再补充解析。 这个篇章主要是对标注好的标签进行可视化,虽然比较简单,但是可以从可视化代码中学习到YOLOv8是如何对标签进行解析的。 import cv2 import numpy as np import os import randomdef read_obb_labels(label_file_path):with open(label_file_path,…

Linux内存管理--系列文章柒——硬件架构

一、引子 之前文章讲解的是系统的虚拟内存&#xff0c;本章讲述这些硬件的架构和系统怎样统一管理这些硬件的。 二、物理内存模型 物理内存模型描述了计算机系统中的物理内存如何由操作系统组织和管理。它定义了物理内存如何划分为单元&#xff0c;如何寻址这些单元以及如何…

yolov8实战——yolov8TensorRT部署(python推理)(保姆教学)

yolov8实战——yolov8TensorRT部署&#xff08;python推理&#xff09;&#xff08;保姆教学&#xff09; 一 、准备好代码和环境安装TensorRt下载代码和安装环境 部署和推理构建ONNX构建engine无torch推理torch推理 最近用到yolov8&#xff0c;但是寻找了一圈才找到了yolov8最…

Java 自定义集合常量

文章目录 Java 自定义集合常量一、普通方法自定义集合常量信息1、定义 Map 集合信息&#xff08;1&#xff09;方法一&#xff1a;使用静态代码块&#xff08;2&#xff09;方法二&#xff1a;简单定义 Map 常量 2、定义 List 集合信息3、定义 Set 集合信息 二、通过 Collectio…

Node.js-path 模块

path 模块 path 模块提供了 操作路径 的功能&#xff0c;如下是几个较为常用的几个 API&#xff1a; 代码实例&#xff1a; const path require(path);//获取路径分隔符 console.log(path.sep);//拼接绝对路径 console.log(path.resolve(__dirname, test));//解析路径 let pa…

一文学会 BootStrap

文章目录 认识BootStrap历史优缺点使用注意安装CDN源码引入包管理器 媒体查询屏幕尺寸的分割点&#xff08;Breakpoints&#xff09;响应式容器网格系统基本使用底层实现.container.row.col、.col-份数 网格嵌套自动布局列 Auto-layout响应式类 Responsive Class 响应式工具类-…

前端根据目录生成模块化路由routes

根据约定大于配置的逻辑&#xff0c;如果目录结构约定俗成&#xff0c;前端是可以根据目录结构动态生成路由所需要的 route 结构的&#xff0c;这个过程是要在编译时 进行&#xff0c;生成需要的代码&#xff0c;保证运行时的代码正确即可 主流的打包工具都有对应的方法读取文…

Qt(二)弹窗类 颜色对话框 字体对话框 资源文件

文章目录 一、QDebug类和QMessagebox类&#xff08;一&#xff09;QDebug类&#xff1a;打印调试类&#xff08;二&#xff09;QMessagebox类&#xff1a;弹窗类2. 修改组件图标&#xff08;1&#xff09;通过ui界面&#xff08;2&#xff09;通过QIcon的方式&#xff08;3&…

SpringBoot新手快速入门系列教程五:基于JPA的一个Mysql简单读写例子

现在我们来做一个简单的读写Mysql的项目 1&#xff0c;先新建一个项目&#xff0c;我们叫它“HelloJPA”并且添加依赖 2&#xff0c;引入以下依赖&#xff1a; Spring Boot DevTools (可选&#xff0c;但推荐&#xff0c;用于开发时热部署)Lombok&#xff08;可选&#xff0c…

如何在前端网页实现live2d的动态效果

React如何在前端网页实现live2d的动态效果 业务需求&#xff1a; 因为公司需要做机器人相关的业务&#xff0c;主要是聊天形式的内容&#xff0c;所以需要一个虚拟的卡通形象。而且为了更直观的展示用户和机器人对话的状态&#xff0c;该live2d动画的嘴型需要根据播放的内容来…

aardio —— 今日减bug

打字就减bug 鼠标双击也减bug 看看有多少bug够你减的 使用方法&#xff1a; 1、将资源附件解压缩&#xff0c;里面的文件夹&#xff0c;放到aardio\plugin\plugins 目录 2、aardio 启动插件 → 插件设置 → 选中“今日减bug” → 保存。 3、重启 aardio&#xff0c;等aa…

高效率写文案软件有哪些?5款免费文案生成器值得拥有

在信息洪流奔涌的当下&#xff0c;文案的重要性愈发凸显。对于文案创作者来说&#xff0c;找到能提高效率的软件至关重要&#xff0c;如&#xff1a;市面上有些不错的文案生成器&#xff0c;它们能够为大家自动生成出高质量文案内容&#xff0c;给文案创作者提供了非常大的帮助…