【Linux】--- 进程的等待与替换

进程的等待与替换

  • 一、进程等待
    • 1、进程等待的必要性
    • 2、获取子进程status
    • 3、进程等待的方法
      • (1)wait()函数
      • (2)waitpid函数
    • 4、多进程创建以及等待的代码模型
    • 5、非阻塞接口 轮询
  • 二、进程替换
    • 1、替换原理
    • 2、替换函数
      • (1)execl函数
      • (2)execlp函数(p:就是文件)
      • (3)execle函数(以e结尾:environment环境变量)
      • (4)execv函数(以v结尾:vector 数组)
      • (5)execvp函数(v+p:数组+文件)
      • (6)execve函数(v+p:数组+环境变量)
    • 3、函数解释
    • 4、命名理解
    • 5、代码演示
      • (1)演示一
      • (2)演示二
      • (3)execv 和 execvp 调用举例
      • (4)execvpe调用举例

一、进程等待

1、进程等待的必要性

  1. 子进程退出,父进程如果不读取子进程的退出信息,子进程就会变成僵尸进程,进而造成内存泄漏。
  2. 进程一旦变成僵尸进程,那么就算是kill -9命令也无法将其杀死,因为谁也无法杀死一个已经死去的进程。
  3. 对于一个进程来说,最关心自己的就是其父进程,因为父进程需要知道自己派给子进程的任务完成的如何。
  4. 父进程需要通过进程等待的方式,回收子进程资源,获取子进程的退出信息。

2、获取子进程status

1、下面进程等待所使用的两个函数wait和waitpid,都有一个status参数,该参数是:一个输出型参数,由操作系统进行填充。

2、如果对status参数传入NULL,表示不关心子进程的退出状态信息。
否则,操作系统会通过该参数,将子进程的退出信息反馈给父进程。

3、对于此,系统当中提供了两个宏来获取退出码和退出信号。

  • WIFEXITED(status):用于查看进程是否是正常退出,本质是检查是否收到信号。
  • WEXITSTATUS(status):用于获取进程的退出码。

需要注意的是,当一个进程非正常退出时,说明该进程是被信号所杀,那么该进程的退出码也就没有意义了。

3、进程等待的方法

(1)wait()函数

  1. 函数原型:pid_t wait(int* status);
  2. 作用:等待任意子进程
  3. 返回值:等待成功返回被等待进程的pid,等待失败返回-1。
  4. 参数:输出型参数,获取子进程的退出状态,不关心可设置为NULL。

例如,创建子进程后,父进程可使用wait函数一直等待子进程,直到子进程退出后读取子进程的退出信息。
在这里插入图片描述

在这里插入图片描述

(2)waitpid函数

  1. 函数原型:pid_t waitpid(pid_t pid, int* status, int options);

  2. 作用:等待指定子进程或任意子进程。

  3. 返回值:
    (1)等待成功返回被等待进程的pid。
    (2)如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0。
    (3)如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在。

    4、参数:
    (1)pid:待等待子进程的pid,若设置为-1,则等待任意子进程。
    (2)status:输出型参数,获取子进程的退出状态,不关心可设置为NULL。
    (3)options:当设置为WNOHANG时,若等待的子进程没有结束,则waitpid函数直接返回0,不予以等待。若正常结束,则返回该子进程的pid。

例如,创建子进程后,父进程可使用waitpid函数一直等待子进程(此时将waitpid的第三个参数设置为0),直到子进程退出后读取子进程的退出信息。

在这里插入图片描述
在父进程运行过程中,我们可以尝试使用kill -9命令将子进程杀死,这时父进程也能等待子进程成功。在这里插入图片描述
注意: 被信号杀死而退出的进程,其退出码将没有意义。

4、多进程创建以及等待的代码模型

上面演示的都是父进程创建以及等待一个子进程的例子,实际上我们还可以同时创建多个子进程,然后让父进程依次等待子进程退出,这叫做多进程创建以及等待的代码模型。

例如,以下代码中同时创建了10个子进程,同时将子进程的pid放入到ids数组当中,并将这10个子进程退出时的退出码设置为该子进程pid在数组ids中的下标,之后父进程再使用waitpid函数指定等待这10个子进程。
在这里插入图片描述
运行代码,这时我们便可以看到父进程同时创建多个子进程,当子进程退出后,父进程再依次读取这些子进程的退出信息。

在这里插入图片描述

5、非阻塞接口 轮询

上述所给例子中,当子进程未退出时,父进程都在一直等待子进程退出,在等待期间,父进程不能做任何事情,这种等待叫做阻塞等待

实际上我们可以让父进程不要一直等待子进程退出,而是当子进程未退出时父进程可以做一些自己的事情,当子进程退出时再读取子进程的退出信息,即非阻塞等待

做法很简单,向waitpid函数的第三个参数potions传入WNOHANG,这样一来,等待的子进程若是没有结束,那么waitpid函数将直接返回0,不予以等待。而等待的子进程若是正常结束,则返回该子进程的pid。

例如,父进程可以隔一段时间调用一次waitpid函数,若是等待的子进程尚未退出,则父进程可以先去做一些其他事,过一段时间再调用waitpid函数读取子进程的退出信息。

在这里插入图片描述
在这里插入图片描述

二、进程替换

1、替换原理

用fork创建子进程后,子进程执行的是和父进程相同的程序(但有可能执行不同的代码分支),若想让子进程执行另一个程序,往往需要调用一种exec类函数。

当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,并从新程序的启动例程开始执行。(其他都不变!)
在这里插入图片描述

  1. 当进行进程程序替换时,有没有创建新的进程?
    进程程序替换之后,该进程对应的task_struct、进程地址空间 以 及页表等 数据结构 都没有发生改变,只有进程在物理内存当中的数据和代码发生了改变,所以并没有创建新的进程,而且进程程序替换前后该进程的pid并没有改变。

2.子进程进行进程程序替换后,会影响父进程的代码和数据吗?

子进程刚被创建时,与父进程共享代码和数据,但当子进程需要进行进程程序替换时,也就意味着子进程需要对其数据和代码进行写入操作,这时便需要将父子进程共享的代码和数据进行写时拷贝,此后父子进程的代码和数据也就分离了,因此子进程进行程序替换后不会影响父进程的代码和数据

2、替换函数

替换函数有六种以exec开头的函数,它们统称为exec函数:

(1)execl函数

int execl(const char *path, const char *arg, …);

第一个参数是要执行程序的路径,第二个参数是可变参数列表,表示你要如何执行这个程序,并以NULL结尾。

例如,要执行的是ls程序

execl("/usr/bin/ls", "ls", "-a", "-i", "-l", NULL);

(2)execlp函数(p:就是文件)

int execlp(const char *file, const char *arg, …);

第一个参数是要执行程序的名字,第二个参数是可变参数列表,表示你要如何执行这个程序,并以NULL结尾。

例如,要执行的是ls程序

execlp("ls", "ls", "-a", "-i", "-l", NULL);

(3)execle函数(以e结尾:environment环境变量)

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

第一个参数是要执行程序的路径,第二个参数是可变参数列表,表示你要如何执行这个程序,并以NULL结尾,第三个参数是你自己设置的环境变量。

例如,你设置了MYVAL环境变量,在mycmd程序内部就可以使用该环境变量。

char* myenvp[] = { "MYVAL=2021", NULL };
execle("./mycmd", "mycmd", NULL, myenvp);

(4)execv函数(以v结尾:vector 数组)

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

第一个参数是要执行程序的路径,第二个参数是一个指针数组,数组当中的内容表示你要如何执行这个程序,数组以NULL结尾。

例如,要执行的是ls程序

char* myargv[] = { "ls", "-a", "-i", "-l", NULL };
execv("/usr/bin/ls", myargv);

(5)execvp函数(v+p:数组+文件)

int execvp(const char *file, char *const argv[]);
第一个参数是要执行程序的名字,第二个参数是一个指针数组,数组当中的内容表示你要如何执行这个程序,数组以NULL结尾。

例如,要执行的是ls程序。

char* myargv[] = { "ls", "-a", "-i", "-l", NULL };
execvp("ls", myargv);

(6)execve函数(v+p:数组+环境变量)

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

第一个参数是要执行程序的路径,第二个参数是一个指针数组,数组当中的内容表示你要如何执行这个程序,数组以NULL结尾,第三个参数是你自己设置的环境变量。

第一个参数是要执行程序的路径,第二个参数是一个指针数组,数组当中的内容表示你要如何执行这个程序,数组以NULL结尾,第三个参数是你自己设置的环境变量。

例如,你设置了MYVAL环境变量,在mycmd程序内部就可以使用该环境变量。

char* myargv[] = { "mycmd", NULL };
char* myenvp[] = { "MYVAL=2021", NULL };
execve("./mycmd", myargv, myenvp);

3、函数解释

  • 这些函数如果调用成功,则加载指定的程序并从启动代码开始执行,不再返回。
  • 如果调用出错,则返回-1。

也就是说,exec系列函数只要返回了,就意味着调用失败。

4、命名理解

这六个exec系列函数的函数名都以exec开头,其后缀的含义如下:

  1. l(list):表示参数采用列表的形式,一一列出。
  2. v(vector):表示参数采用数组的形式。
  3. p(path):表示能自动搜索环境变量PATH,进行程序查找。(其实参数就是文件~)
  4. e(env):表示可以传入自己设置的环境变量。

5、代码演示

(1)演示一

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

(2)演示二

在这里插入图片描述

在这里插入图片描述如果替换失败,就直接忽视,继续执行原来的进程代码!

(3)execv 和 execvp 调用举例

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

代码:

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<wait.h>// 多进程版本
int main()
{printf("testexec ... begin!\n");pid_t id = fork();if(id == 0){// childprintf("I am child process,pid:%d\n",getpid());sleep(2);char* const argv[]={(char*)"ls",(char*)"-a",(char*)"-l",(char*)"--color",NULL};// execv("/usr/bin/ls",argv);execvp("ls",argv);}// fatherint status = 0;pid_t rid = waitpid(id,&status,0);if(rid > 0){printf("father wait success,child exit code:%d\n",WEXITSTATUS(status));}else {printf("father wait failed!\n");}printf("testexec ... end!\n");return 0;
}

在这里插入图片描述
在这里插入图片描述

(4)execvpe调用举例

int execvpe(const char *file, char *const argv[],char *const envp[]);

代码:

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<wait.h>
#include<stdlib.h>// 多进程版本
int main()
{printf("testexec ... begin!\n");pid_t id = fork();if(id == 0){// child// 我的父进程本身就有一批环境变量,从bash来,自己想添加可以使用putenvputenv("HHHH=333333333");// 头文件 stdlib.hchar* const argv[]={(char*)"mypragma",(char*)"-a",(char*)"-b",NULL };printf("I am child process,pid:%d\n",getpid());sleep(2);extern char** environ;execvpe("./mypragma",argv,environ);}// fatherint status = 0;pid_t rid = waitpid(id,&status,0);if(rid > 0){printf("father wait success,child exit code:%d\n",WEXITSTATUS(status));}else {printf("father wait failed!\n");}printf("testexec ... end!\n");return 0;
}

在这里插入图片描述
事实上,只有execve是真正的系统调用,其它六个函数最终都调用 execve,所以execve在man手册 第2节,其它函数在man手册第3节。这些函数之间的关系如下图所示。

在这里插入图片描述

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

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

相关文章

intel x99主板设置上电服务器自动启动

作者&#xff1a;吴业亮 博客&#xff1a;wuyeliang.blog.csdn.net 1、选择IntelRCStetup–>PCH state after G3 -->ON PCH state after G3&#xff1a;是指系统完全关闭电源的状态&#xff0c;此时主板上只有RTC&#xff08;实时时钟&#xff09;电源。这个选项决定了系…

机器学习-归一化,标准化

标准化&#xff08;Standardization&#xff09;是将数据按比例缩放&#xff0c;使其具有特定的统计特征&#xff0c;通常是将数据的均值调整为0&#xff0c;标准差调整为1。标准化是一种常见的数据预处理技术&#xff0c;特别是在进行机器学习时&#xff0c;通常会使用标准化来…

zerotier搭建虚拟局域网,自建planet

基于该开源项目 自建planet节点&#xff0c;更快速&#xff0c;更安全 本教程依据docker-zerotier-planet 项目文档书写&#xff0c;并以linux(centos 7)和windows作为示例&#xff0c;需要其他系统配置方法&#xff0c;可移步项目文档 一. 前置资源 具有外网ip的服务器 后面…

Spring Boot + MyBatis-Flex 配置 ProxySQL 的完整指南

✅ Spring Boot MyBatis-Flex 配置 ProxySQL 的完整指南 下面是一个详细的教程&#xff0c;指导您如何在 Spring Boot 项目中使用 MyBatis-Flex 配置 ProxySQL 进行 读写分离 和 主从同步 的数据库访问。 &#x1f3af; 目标 在 Spring Boot 中连接 ProxySQL。使用 MyBatis-…

如何解决Webview和H5缓存问题,确保每次加载最新版本的资源

WebView 用于加载 H5 页面是常见的做法&#xff0c;它能够加载远程的 HTML、CSS、JavaScript 资源&#xff0c;并且让 Web 应用嵌入到原生 App 中。然而&#xff0c;WebView 的缓存机制有时会导致用户看到的是旧版本的页面或资源&#xff0c;尤其是在 H5 发版后&#xff0c;iOS…

屏幕轻触间:触摸交互从 “感知” 到 “智算” 的隐秘路径

从用户点击屏幕到前端感知及数据处理全流程剖析 引言 在移动智能设备与触摸交互技术深度融合的当下&#xff0c;当我们的手指轻触手机屏幕&#xff0c;一系列复杂且精妙的技术流程便瞬间启动。这一过程涵盖硬件层、驱动层、操作系统层、应用层&#xff0c;甚至延伸到后端的数…

微调的种类

微调的种类 flyfish 全参数微调&#xff08;Full Fine-Tuning&#xff09;&#xff1a; 对预训练模型的所有参数进行调整&#xff0c;以优化其在特定任务上的性能。 指令微调&#xff08;Instruction Fine-Tuning&#xff09;&#xff1a; 通过提供特定任务的明确指令或示例来…

C# 配置文件:app.config 和 web.config

一、引言 在 C# 的应用开发中&#xff0c;配置文件就像是幕后的大管家&#xff0c;默默管理着应用程序的各种设置。今天&#xff0c;我们就来深入探索一下 C# 中极为重要的两个配置文件&#xff1a;app.config 和 web.config。无论是开发 Windows 应用程序&#xff0c;还是构建…

java 设计模式 工厂模式

什么是工厂模式 工厂模式&#xff08;Factory Pattern&#xff09;是一种创建型设计模式&#xff0c;它通过定义一个接口或抽象类来创建对象&#xff0c;但由子类决定具体实例化哪个类。简单来说&#xff0c;工厂模式将对象的实例化过程封装起来&#xff0c;客户端通过工厂方法…

[创业之路-248]:《华为流程变革:责权利梳理与流程体系建设》华为流程的前端拉动后端,与计算机软件的前端应用与后端程序的类比关系

华为的前端拉动后端模式与计算机前端应用与后端程序的类比关系&#xff0c;虽然两者属于不同的领域&#xff0c;但在某些方面存在有趣的相似性。以下是对这两者的类比关系的详细探讨&#xff1a; 一、华为的前端拉动后端模式 定义与特点&#xff1a; 华为的前端拉动后端模式是…

深入Node.js集群:原理、优势与搭建实战,如何应对高并发

文章目录 一、Node.js 集群简介二、Node.js 集群原理剖析2.1 主从模型2.2 负载均衡机制2.3 进程间通信&#xff08;IPC&#xff09; 三、Node.js 集群优势详解3.1 性能提升3.2 高可用性3.3 资源利用率优化 四、Node.js 集群搭建实战4.1 准备工作4.2 创建主控制节点4.3 工作节点…

数字普惠金融对新质生产力的影响研究(2015-2023年)

基于2015—2023年中国制造业上市公司数据&#xff0c;探讨了数字普惠金融对制造业企业新质生产力的影响及作用机理。研究发现&#xff0c;数字普惠金融有助于促进制造业企业新质生产力的发展&#xff0c;尤其是在数字普惠金融的使用深度较大的情况下&#xff0c;其对新质生产力…

数据仓库基础常见面试题

1.数据仓库是什么 ‌数据仓库&#xff08;Data Warehouse&#xff09;是一个面向主题的、集成的、非易失的、随时间变化的数据集合&#xff0c;用于支持企业的管理决策‌。它不同于传统的操作型数据库&#xff0c;后者主要用于处理日常业务交易和实时查询&#xff0c;而数据仓库…

记一次OpenEuler Linux磁盘分区表损坏的数据恢复

问题复现 原本有一台GIS地图服务器存放大量数据&#xff0c;突然有一天磁盘满了&#xff0c;于是运维人员照常进行磁盘扩容。但由于误操作&#xff0c;导致使用fdisk的时候把分区表损坏了&#xff0c;表现如下&#xff1a; 这里可以看到启动时能看到xvda被分为了xvda1和xvda2…

分布式数据存储基础与HDFS操作实践(副本)

以下为作者本人撰写的报告&#xff0c;步骤略有繁琐&#xff0c;不建议作为参考内容&#xff0c;可以适当浏览&#xff0c;进一步理解。 一、实验目的 1、理解分布式文件系统的基本概念和工作原理。 2、掌握Hadoop分布式文件系统&#xff08;HDFS&#xff09;的基本操作。 …

【数据结构学习笔记】19:跳表(Skip List)

介绍 跳表是一个能在 O ( n l o g n ) O(nlogn) O(nlogn)时间完成查找、插入、删除的数据结构&#xff0c;相比于树形结构优点就是很好写&#xff08;所以也用于实现Redis ZSet&#xff09;。其核心思想就是维护一个元素有序的&#xff0c;能随机提升索引层数的链表。最下面一…

如何使用 PHP 操作亚马逊 S3 对象云存储

以下是使用PHP与亚马逊S3对象云存储&#xff08;也有其他支持S3协议的云存储服务&#xff0c;原理类似&#xff09;进行交互的常见文档接口使用示例&#xff0c;涵盖了基本的操作如上传文件、下载文件、删除文件、列举文件等内容。 ### 前提条件 1. 首先&#xff0c;你需要获取…

APP推荐:全新TV端来了,8K原画电视版

▌ 软件介绍 B站都不陌生吧&#xff0c;一个能追番、学习、娱乐的多元平台&#xff0c;之前也分享过几款第三方TV端&#xff0c;其中的BV最近更新了全新版本。 使用了全新的UI界面&#xff0c;由之前的顶部菜单栏改成了侧边布局&#xff0c;已解锁限制&…

Pcl联合Qt显示点云

基于vs2022 勾选opengl&#xff0c;openglwidgets&#xff0c;并将widget控件提示为QVTKOpenGLNativeWidget Qt_Pcls.h #pragma once #include <QtWidgets/QMainWindow> #include "ui_Qt_Pcls.h" #include <vtkGenericOpenGLRenderWindow.h> #include &…

pip install transformers教程

直接pip install transformers会报错&#xff0c;报错内容如下&#xff1a; Collecting safetensors>0.3.1 (from transformers)Using cached safetensors-0.5.2.tar.gz (66 kB)Installing build dependencies ... doneGetting requirements to build wheel ... donePrepar…