当前位置: 首页 > news >正文

[Linux] 进程创建、退出和等待

标题:[Linux] 进程创建、退出和等待

个人主页@水墨不写bug

(图片来源于AI)

目录

一、进程创建fork()

1) fork的返回值:

2)写时拷贝

​编辑3)fork常规用法

4)fork调用失败的原因

二、什么是进程退出

1)exit()函数于系统调用接口_exit()有什么区别?

三、僵尸进程和进程等待

1)父进程处理僵尸进程就需要进程等待

2)阻塞等待 

3)非阻塞等待:

 4)输出型参数status:

 总结:


正文开始:

一、进程创建fork()

         fork()是Linux操作系统提供的系统调用,作用是从一个已经存在的进程中创建一个新进程。新进程为子进程,原进程为父进程。

//头文件
#include <unistd.h>//函数原型
pid_t fork(void);//返回值:子进程中返回0,父进程返回子进程id,出错返回-1

 

进程调用fork,当控制转移到内核中的fork代码后,内核做:

  •         分配新的内存块和内核数据结构给子进程
  •         将父进程部分数据结构内容拷贝至子进程
  •         添加子进程到系统进程列表当中
  •         fork返回,开始调度器调度

        具体创建过程的内存图示见《Linux:初识进程地址空间》 ,子进程创建后这里仅仅给出一张图:

         最重要的是:当一个进程调用fork之后,就有两个二进制代码相同的进程。而且它们都运行到相同的地方。如下面的例子:

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>int main()
{printf("fork之前 我的pid:%d\n",getpid());pid_t id = fork();printf("fork之后 我的pid:%d, fork的返回值:%d\n",getpid(),id);return 0;
}

        运行之后,结果如图:

         分析:

        在fork之前,只有一个进程,pid=48247;

        fork之后,父进程(pid=48247)创建出子进程(pid=48248):从父子进程的pid临近和fork给子进程的返回值为0,给父进程的返回值为子进程的pid可以看出来。

         fork之后,父子进程都执行到fork函数这一行,于是,fork之前的代码不会被执行,之后的代码会被父子进程各自执行一次

1) fork的返回值:

        给子进程返回0;

        给父进程返回子进程的pid;

        如果出错了,则子进程没有被创建出来,那么给仅有的一个进程(父进程)返回-1;

2)写时拷贝

        写时拷贝(copy-on-write)是一种内存管理技术,用于优化内存使用和提高性能。它是一种延迟拷贝的策略,在创建副本之前,共享资源将不会被复制。

        写时拷贝的原理是,当一个对象需要被拷贝时,不会立即进行拷贝操作。而是让新对象与原对象共享同一份资源。当其中一个对象修改了该资源时,才会将资源复制到新的对象上。这样可以减少内存的使用,避免了不必要的复制操作。

3)fork常规用法

        一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如,父进程等待客户端请求,生成子进程来处理请求。

        一个进程要执行一个不同的程序。例如子进程从fork返回后,调用exec函数。(进程替换函数)

4)fork调用失败的原因

        系统中有太多的进程;

        实际用户的进程数超过了限制;


二、什么是进程退出

         我们在当初学习C语言的时候,经常会malloc空间,但是动态内存开辟是会有失败的时候,malloc的最保险的用法:

    int size = 10;int* arr = (int*)malloc(size*sizeof(int));if(arr == NULL){perror("malloc fail:");exit(-1);}

         如果malloc失败,通常是非常严重的错误,这个时候进程已经没有必要继续运行下去了,这时候选择打印错误信息,如果调用exit函数退出。

        上述的进程退出只是进程退出的一种场景,其实进程想要退出,无非只有三种场景

1)代码运行完毕;

2)结果正确代码运行完毕,结果不正确;

3)代码异常终止

         当一个进程退出,我们在Linux终端可以使用:

echo $?

         命令查看最近一次进程退出的退出码。

        如果最近的一个进程正常退出,返回值是0;

 一个进程退出有什么方式?其实无非就是:

        1)从main函数返回;

        2)调用: exit();

        3)调用系统调用接口:   _exit();

对于其他的退出方式,一般就是我们主动退出:ctrl+C;

或者遇到空指针,或者被断言断死,其实这些退出方式有一个统称:被系统的信号杀死。

1)exit()函数于系统调用接口_exit()有什么区别?

         这两个函数的最本质功能是一样的,都是让进程退出,但是exit() 函数是对系统调用_exit()函数的封装。

        _exit函数是系统调用,exit是C语言的库函数。

进程调用_exit()会直接退出,但是调用exit会在退出之前做一些善后的处理:

        1. 执行用户通过 atexit或on_exit定义的清理函数。

        2. 关闭所有打开的流,所有的缓存数据均被写入(刷新缓冲区)

        3. 调用_exit

三、僵尸进程和进程等待

        在Linux系统中,僵尸进程(Zombie Process)是指已经结束执行的进程,但是其父进程还没有对其进行完全的清理操作,导致进程的资源没有被释放。

        僵尸进程的产生是因为操作系统在进程结束时不会立即清理相关的资源,而是会将其转变为僵尸进程,等待父进程来处理。父进程需要通过调用wait()或waitpid()系统调用来获取子进程的退出状态,并对其进行清理,释放相应的资源。如果父进程没有处理僵尸进程,那么僵尸进程会一直存在于系统中,占用系统资源。

        僵尸进程通常不会对系统造成直接的危害,因为它们已经停止运行。然而,如果有大量的僵尸进程存在,会浪费系统的进程表资源,并可能导致进程表耗尽的问题。此外,僵尸进程也可能是父进程出现问题或错误的一个指示,比如父进程无法正确处理子进程的退出状态。

1)父进程处理僵尸进程就需要进程等待

        父进程需要调用wait()/waitpid()等方法等待子进程退出。

2)阻塞等待 

        接口wait():等待任意一个子进程退出,但是在等待的过程中父进程什么事都干不了,这样的等待称为“阻塞等待”。

//头文件
#include<sys/types.h>
#include<sys/wait.h>pid_t wait(int*status);
//返回值:
//成功返回被等待进程pid,失败返回-1。//参数:
//输出型参数,获取子进程退出状态,不关心则可以设置成为NULL

如果想要让父进程在等待的过程中做一些事情,就需要另一个接口:waitpid()

//头文件
#include<sys/types.h>
#include<sys/wait.h>pid_ t waitpid(pid_t pid, int *status, int options);//返回值:
//当正常返回的时候waitpid返回收集到的子进程的进程pid;//如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;//如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;//参数:
//pid:
//    Pid = -1, 等待任一个子进程,与wait等效。
//    Pid > 0 . 等待其进程ID与pid相等的子进程。
//status:
//    WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
//    WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)
//options:
//    WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID

3)非阻塞等待:

        waitpid()接口如果设置了MNOHANG,那么进程走到这个接口之后,会查看一次子进程是否已经退出,如果已经退出,我们就可根据此时的返回值设置循环的出口;

        如果没有退出,则进程会执行waitpid() 之后的代码逻辑,直到下一次循环再次到达waitpid()这个接口处,再次查看,继续循环。

非阻塞等待实例:


void oper()
{sleep(1);printf("等待不妨碍做其他事\n");
}int main()
{pid_t id = fork();if(id == 0){printf("我是子进程,5秒后退出\n");sleep(5);exit(0);}else{int status = 0;printf("我是父进程,等待子进程退出\n");while(1){pid_t rid = waitpid(id,&status,WNOHANG);if(rid > 0){printf("父进程等到子进程退出\n");break;}oper();}}return 0;
}

运行结果:

 4)输出型参数status:

        什么是输出型参数:输出型参数就是我们穿一个参数,他的值是由操作系统填充的,因此我们在传参的时候需要传地址

        如果传递NULL,表示不关心子进程的退出状态信息。

        如果传递了status的地址,操作系统会根据该参数,将子进程的退出信息反馈给父进程。

        status不能简单的当作整形来看待,需要当作位图来看待,具体细节如下图(status是32位整形,高16位并不携带信息,只有status低16比特位携带信息):

 对于低16位:

        如果正常退出(没有被信号杀掉):那么低8位为0,次低8位表示退出码,这里的退出码,就是函数return的返回值,也是exit()括号内传的值。退出信号的意义是由我们自己赋予的。

        如果异常退出(进程被信号杀掉):退出码虽然可以手动获得,但是已经没有意义了,因为已经发生重大错误,导致进程都没有执行完就退出了 。这时低7位表示进程的退出信号,也就是操作系统发送给进程的异常信号。第8位暂时不考虑。

        低7位正好是2的七次方:64个标识,正好对应kill命令给进程发送的终止信号的个数:

 

 总结:

        正常退出,次低8位 退出码;

        异常退出,低7位 退出信号;

其实,为了便于记忆,有两个专门对status处理的

        

WIFEXITED:

        如果子进程正常退出,返回真;

WEXITSTATUS:

        返回status的次低8位退出码。

实例:


int main()
{pid_t id = fork();if(id == 0){int* p = NULL;*p = 10;exit(0);}else{int status = 0;wait(&status);printf("%d\n",status);if(WIFEXITED(status)){printf("程序正常退出:%d\n",WEXITSTATUS(status));}else{printf("程序挂了:%d\n",(status&0x7f));}}return 0;
}

运行结果:


完~

未经作者同意禁止转载 

相关文章:

[Linux] 进程创建、退出和等待

标题&#xff1a;[Linux] 进程创建、退出和等待 个人主页水墨不写bug &#xff08;图片来源于AI&#xff09; 目录 一、进程创建fork&#xff08;&#xff09; 1&#xff09; fork的返回值&#xff1a; 2&#xff09;写时拷贝 ​编辑3&#xff09;fork常规用法 4&#xff…...

微软推出针对个人的 “AI伴侣” Copilot 会根据用户的行为模式、习惯自动进化

微软推出了为每个人提供的“AI伴侣”Copilot&#xff0c;它不仅能够理解用户的需求&#xff0c;还能根据用户的日常习惯和偏好进行适应和进化。帮助处理各种任务和复杂的日常生活场景。 它能够根据用户的生活背景提供帮助和建议&#xff0c;保护用户的隐私和数据安全。Copilot…...

【QT】QT入门

个人主页~ QT入门 一、简述QT1、什么是QT2、QT的优势3、应用场景 二、QT的基本使用1、新建项目&#xff08;1&#xff09;选择项目模版&#xff08;2&#xff09;选择项目路径&#xff08;3&#xff09;选择构建系统&#xff08;4&#xff09;填写类信息设置界面&#xff08;5&…...

Linux 6.11版本发布

Linux 6.11版本的发布是Linux社区的一个重要里程碑&#xff0c;它不仅在实时计算、性能优化方面取得了显著进展&#xff0c;还在安全性上迈出了关键一步。 一、实时计算与性能优化 1.io_uring子系统支持 Linux 6.11引入了io_uring子系统的增强功能&#xff0c;特别是支持了b…...

CSS 参考手册

CSS 参考手册 概述 CSS(层叠样式表)是一种用于描述HTML或XML文档样式的样式表语言。它用于控制网页的布局和外观,使网页设计更加美观和响应式。CSS可以定义文本颜色、字体、布局、响应式设计等,是网页设计和开发中不可或缺的一部分。 基础语法 CSS的基本语法由选择器和…...

数据采集工具sqoop介绍

文章目录 什么是sqoop?一、Sqoop的起源与发展二、Sqoop的主要功能三、Sqoop的工作原理四、Sqoop的使用场景五、Sqoop的优势六、Sqoop的安装与配置 sqoop命令行一、Sqoop简介与架构二、Sqoop特点三、Sqoop常用命令及参数四、使用示例五、注意事项 什么是sqoop? Sqoop是一款开…...

扫盲:写给UI设计师的SCADA系统知识点

一、SCADA是什么&#xff0c;及其组成。 SCADA&#xff08;Supervisory Control And Data Acquisition&#xff0c;监控与数据采集系统&#xff09;是一种用于实时监控、控制和数据采集的自动化系统。 SCADA的组成部分&#xff1a; - 人机界面&#xff08;HMI*&#xff1a;提…...

类的特殊成员函数——三之法则、五之法则、零之法则

系统中的动态资源、文件句柄&#xff08;socket描述符、文件描述符&#xff09;是有限的&#xff0c;在类中若涉及对此类资源的操作&#xff0c;但是未做到妥善的管理&#xff0c;常会造成资源泄露问题&#xff0c;严重的可能造成资源不可用。或引发未定义行为&#xff0c;进而…...

计算机毕业设计 智慧物业服务系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…...

Python软体中使用SpaCy进行命名实体识别

Python软体中使用SpaCy进行命名实体识别 命名实体识别(Named Entity Recognition,NER)是自然语言处理(NLP)中的一个重要任务,它涉及识别文本中的命名实体,例如人名、地名、组织名等。SpaCy是一种流行的NLP库,提供了高效的NER功能。在本文中,我们将介绍如何使用SpaCy进…...

华为云技术深度解析:以系统性创新加速智能化升级

华为云技术深度解析&#xff1a;以系统性创新加速智能化升级 在当今数字化转型的浪潮中&#xff0c;云计算作为关键的基础设施&#xff0c;正以前所未有的速度推动着各行各业的智能化升级。作为全球领先的云服务提供商&#xff0c;华为云凭借其深厚的技术积累和创新实力&#…...

推理攻击-Python案例

1、本文通过推理攻击的方式来估计训练集中每个类别的样本数量、某样本是否在训练集中。 2、一种简单的实现方法&#xff1a;用模型对训练数据标签进行拟合&#xff0c;拟合结果即推理为训练集中的情况。 3、了解这些案例可以帮助我们更好的保护数据隐私。 推理攻击&#xff08;…...

find_box_3d

参数 &#xff08;ObjectModel3DScene, SideLen1, SideLen2, SideLen3, MinScore, GenParam : GrippingPose, Score, ObjectModel3DBox, BoxInformation) 入参介绍 1&#xff0c;ObjectModel3DScene&#xff0c; 输入的3d模型&#xff0c;这个模型最好是由xyx三通道点…...

Visual Studio2017编译GDAL3.0.2源码过程

一、编译环境 操作系统&#xff1a;Windows 10企业版 编译工具&#xff1a;Visual Studio 2017旗舰版 源码版本&#xff1a;gdal3.0.2 二、生成解决方案 打开Visual Studio 2017的x64本机生成工具&#xff0c;切换到gdal3.0.2源码根目录&#xff1b;执行generate_vcxproj.b…...

计算机网络——email

pop3拉出来 超出ASCII码范围就不让传了 这样就可以传更大的文件...

【Linux】信号知识三把斧——信号的产生、保存和处理

目录​​​​​​​ 1、关于信号的前置知识 1.1.什么是信号&#xff1f; 1.2.为什么要学习信号&#xff1f; 1.3.如何学习信号&#xff1f; 1.4.一些常见的信号 1.5.信号的处理方式 1.6.为什么每一个进程都可以系统调用&#xff1f; 2.信号的产生 2.1.kill命令产生信号…...

【国庆要来了】基于Leaflet的旅游路线WebGIS可视化实践

前言 转眼2024年的国庆节马上就要来临了&#xff0c;估计很多小伙伴都计划好了旅游路线。金秋十月&#xff0c;不管是选择出门去看看风景&#xff0c;还是选择在家里看人。从自己生活惯了的城市去别人生活惯了的城市&#xff0c;去感受城市烟火、去感受人文风景&#xff0c;为2…...

Element-UI Plus 暗黑主题切换及自定义主题色

1. 暗黑主题切换 在main.js中引入下面文件 import element-plus/theme-chalk/dark/css-vars.css安装 vueuse/core pnpm add vueuse/coreApp.vue 添加下面代码 使用了 useDark() 的页面才会从 localStorage中读取当前主题状态&#xff0c;否则&#xff0c;刷新页面就会恢复默…...

人工智能与机器学习原理精解【31】

文章目录 卷积神经网络CNN定义数学原理与公式计算与定理架构例子例题 全连接层的前馈计算定义数学原理与公式计算过程示例 参考文献 卷积神经网络 CNN 即卷积神经网络&#xff08;Convolutional Neural Networks&#xff09;&#xff0c;是一类包含卷积计算且具有深度结构的前…...

如何安全地大规模部署 GenAI 应用程序

大型语言模型和其他形式的生成式人工智能(GenAI) 的广泛使用带来了许多组织可能没有意识到的安全风险。幸运的是&#xff0c;网络和安全提供商正在寻找方法来应对这些前所未有的威胁。 随着人工智能越来越深入地融入日常业务流程&#xff0c;它面临着泄露专有信息、提供错误答…...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

ESP32读取DHT11温湿度数据

芯片&#xff1a;ESP32 环境&#xff1a;Arduino 一、安装DHT11传感器库 红框的库&#xff0c;别安装错了 二、代码 注意&#xff0c;DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...