【Linux探索学习】第十七弹——进程终止:深入解析操作系统中的进程终止机制

Linux学习笔记:

https://blog.csdn.net/2301_80220607/category_12805278.html?spm=1001.2014.3001.5482

前言:

在操作系统中,进程终止是一个至关重要的阶段,它标志着进程的生命周期结束。进程终止可能是因为任务完成,也可能是因为异常或外部干预。本文将详细讲解操作系统中的进程终止相关知识,包括终止的原因、类型、实现方式、Linux系统中的具体操作,以及其影响和管理策略,并配以表格和代码示例,帮助全面掌握这一主题。


目录

一、什么是进程终止?

二、进程终止的主要原因

三、进程终止的类型

四、Linux中的进程终止实现

4.1 运行完毕且正常终止

4.1.1 使用return终止进程

4.1.2 使用exit终止进程

4.2 errno常量和strerror函数

4.2.1 strerror函数

4.2.2 errno常量

4.3 异常终止:abort

4.4 强制终止:kill

4.4 子进程资源回收:wait 和 waitpid

五、进程终止的影响

5.1 资源释放

5.2 僵尸进程

如何避免僵尸进程?

六、信号与进程终止

常见信号与作用

示例代码:捕获SIGTERM信号

七、进程终止的常见问题与解决

7.1 僵尸进程问题

7.2 非预期终止

八、总结


一、什么是进程终止?

进程终止(Process Termination)是操作系统中进程生命周期的最后一个阶段,意味着操作系统回收该进程的所有资源,包括内存、文件描述符、CPU时间等,使这些资源可以被其他进程使用。


二、进程终止的主要原因

进程可能因多种原因终止:

终止原因描述
正常终止进程完成所有任务后自然结束,例如程序执行到return语句或调用exit函数。
异常终止由于未处理的错误或异常导致进程终止,例如除以零、非法访问内存等。
外部干预进程被操作系统或其他进程强制终止,例如接收到SIGKILL信号。
父进程终止当父进程终止且子进程未被接管时,子进程可能成为孤儿进程,由initsystemd进程接管。
资源耗尽进程因超出系统资源限制(如内存、文件句柄等)被操作系统强制终止。

三、进程终止的类型

进程终止根据触发方式可以分为以下几类:

类型触发方式常见场景
正常终止调用exit()、返回主函数程序完成任务后自然结束。
异常终止未处理的错误或调用abort()例如访问非法地址、未处理的信号等。
强制终止外部进程调用kill()、操作系统干预父进程发送SIGKILL信号或管理员手动终止进程。
核心转储终止错误导致生成核心转储文件例如段错误(SIGSEGV)导致的异常。

一般进程终止的场景包含一下三种:

1. 代码运行完毕,结果正常

2. 代码运行完毕,结果不正常

3. 代码异常终止

下面我们会对上面的内容做出讲解


四、Linux中的进程终止实现

在Linux操作系统中,进程终止主要通过以下系统调用和信号实现:

4.1 运行完毕且正常终止

4.1.1 使用return终止进程

我们平时用的最多的方式就是return,我们先来看下面一个简单的代码

  #include<stdio.h>                    int main()   {   printf("This is a test message");return 0;}        

我们平时所写的代码main函数中一般都有一个返回值,那么这个返回值是干什么的呢?

main函数返回值是返回给进程看的,本质表示:进程运行完成时是否是正确的结果,如果是一般返回0,如果不是返回其它数字代表不同的退出信息(退出码)

我们可以通过这个指令打印退出码:

echo $?

4.1.2 使用exit终止进程

exit系统调用用于正常终止进程,并返回一个状态码给操作系统或父进程。

我们使用exit一般是在进程正常终止但没有正常执行的场景,或者是在合适的地方进行截停的场景,我们来看下面一段代码:

#include<stdio.h> 
#include<stdlib.h>                                                                                                                                                                                           
void print()      
{                 printf("hello linux\n");printf("hello linux\n");printf("hello linux\n");printf("hello linux\n");exit(20);     printf("hello linux\n");printf("hello linux\n");
}                 
int main()        
{                 print();      return 10;    
}                 

我们来看一下上面内容的执行结果和返回值:

我们发现返回值是exit中的返回值,并不是return的返回值,而且打印也只执行了四行,所以我们可以知道带有exit的进程,在执行到它时会直接返回,并不会再继续执行后面的内容,返回值也返回exit的返回值,这一点与return有较大差别


4.2 errno常量和strerror函数

4.2.1 strerror函数

上面我们提到我们可以通过不同的退出码来代表不同的错误信息,那么不同的退出码究竟各自代表什么信息呢?我们可以通过strerror函数来查看

比如我们来看一下退出码0到10所代表的信息:

#include<stdio.h>
#include<string.h>
int main()
{for(int i=0;i<=10;i++){printf("%d: %s\n",i,strerror(i));}return 0;
}                

运行结果:

4.2.2 errno常量

上面我们讲到进程在退出是会有退出码,我们可以通过echo来查看退出码,那我们如何获取呢?

C/C++中其实还定义了一个叫errno的常量来记录错误码

所以我们就可以将errno常量与strerror函数结合使用,用errno来记录进程的错误码,然后传给strerror函数得到错误信息,比如下面的例子:

#include<stdio.h> 
#include<unistd.h>                                                                                                                                                                                           
#include<string.h>
#include<stdlib.h>
#include<errno.h>     //注意要带好头文件
int main()        
{                 int ret=0;    char *p=(char*)malloc(1000*1000*1000*4);    //这个扩容肯定会出错的,因为扩容空间太大了if(p==NULL)   {             printf("mallo error, %d:%s\n",errno,strerror(errno));   //errno会记录错误码,将它传到strerror中就可以得到错误信息ret=errno;    //将错误码作为返回值返回,从而让父进程得到返回信息}             else          {             printf("malloc success\n");}             return ret;   
}                 

运行结果:


4.3 异常终止:abort

4.2和4.3都牵扯到了信号的内容,这里我们主要还是以了解为主,后期我们会详细讲解信号的知识

abort函数用于非正常终止进程,通常在遇到不可恢复的错误时调用。

示例代码:abort

#include <stdlib.h>
#include <stdio.h>int main() {printf("遇到严重错误,程序终止!\n");abort();  // 异常终止return 0;  // 不会被执行
}

调用abort会产生一个信号(SIGABRT),通常会生成一个核心转储文件供调试使用。


4.4 强制终止:kill

kill系统调用或命令用于向目标进程发送信号,例如SIGKILL信号会立即强制终止目标进程。

示例代码:kill

#include <signal.h>
#include <unistd.h>
#include <stdio.h>int main() {pid_t pid = fork();if (pid == 0) {// 子进程while (1) {printf("子进程正在运行: PID = %d\n", getpid());sleep(1);}} else if (pid > 0) {// 父进程sleep(5);printf("终止子进程: PID = %d\n", pid);kill(pid, SIGKILL);  // 发送SIGKILL信号}return 0;
}

执行结果:

我们发现子进程在被执行了五次后被终止掉了,对应的就是代码中执行了五次后会执行kill指令杀死进程


4.4 子进程资源回收:waitwaitpid

进程等待与回收我们会在下一篇详细讲解

当子进程终止后,其状态会保留在系统中,直到父进程回收。这种未被回收的子进程称为僵尸进程

示例代码:回收子进程资源

#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>int main() {pid_t pid = fork();if (pid == 0) {// 子进程printf("子进程开始: PID = %d\n", getpid());sleep(2);printf("子进程结束\n");} else if (pid > 0) {// 父进程int status;wait(&status);  // 等待子进程终止if (WIFEXITED(status)) {printf("子进程正常终止,状态码: %d\n", WEXITSTATUS(status));}}return 0;
}

执行结果:


五、进程终止的影响

5.1 资源释放

进程终止后,操作系统会回收以下资源:

  • 内存:代码段、数据段、堆栈等。
  • 文件描述符:关闭该进程打开的所有文件。
  • CPU时间:释放进程的时间片。

5.2 僵尸进程

当子进程终止但父进程未调用waitwaitpid回收其状态时,子进程会变成僵尸进程

如何避免僵尸进程?
  1. 父进程调用waitwaitpid回收子进程。
  2. 使用信号处理机制,如捕获SIGCHLD信号。

六、信号与进程终止

常见信号与作用

信号描述默认行为
SIGKILL强制终止进程,无法捕获或忽略。终止
SIGTERM请求终止进程,进程可以选择捕获或忽略。终止
SIGABRT异常终止进程,通常由abort触发。终止并生成核心转储
SIGCHLD子进程终止或停止时通知父进程。忽略
示例代码:捕获SIGTERM信号
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>void handle_sigterm(int sig) {printf("接收到SIGTERM信号,进程终止\n");exit(0);
}int main() {signal(SIGTERM, handle_sigterm);  // 注册信号处理函数while (1) {printf("程序正在运行...\n");sleep(2);}return 0;
}

七、进程终止的常见问题与解决

7.1 僵尸进程问题

问题:父进程未回收子进程,导致系统中出现僵尸进程。

解决

  • 调用waitwaitpid
  • 使用SIGCHLD信号处理函数自动回收。

7.2 非预期终止

问题:进程意外终止导致数据未保存。

解决:通过信号处理函数捕获终止信号,并在终止前完成必要的清理工作。


八、总结

进程终止是操作系统中管理资源的重要环节。通过本文的讲解,我们了解了进程终止的主要原因、类型以及Linux中的具体实现方式。进程终止不仅影响单个进程的生命周期,还对系统资源的利用和稳定性产生重要影响。

通过合理地使用exitkillwait等系统调用,以及信号机制,可以高效管理进程终止,避免僵尸进程问题,提高系统性能和可靠性。希望通过本文的详细分析和代码示例,你能更加深入理解操作系统的这一重要机制!

本篇笔记:


感谢各位大佬观看,创作不易,还请各位大佬点赞支持!!!

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

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

相关文章

介绍一下strupr(arr);(c基础)

hi , I am 36 适合对象c语言初学者 strupr(arr)&#xff1b;函数是把arr数组变为大写字母 格式 #include<string.h> strupr(arr); 返回值为arr 链接分享一下arr的意义(c基础)(必看)(牢记)-CSDN博客 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #incl…

【VRChat 全身动捕】VIVE 手柄改 tracker 定位器教程,低成本光学动捕解决方案(持续更新中2024.11.26)

更新 0.0.1&#xff08;2024/11/26&#xff09;&#xff1a; 1.解决了内建蓝牙无法识别、“steamVR 蓝牙不可用” 的解决方案 2.解决了 tracker 虽然建立了连接但是在 steamVR 界面上看不到的问题 3.解决了 VIVE 基站1.0 无法被蓝牙识别 && 无法被 steamVR 搜索到 &…

Web 端语音对话 AI 示例:使用 Whisper 和 llama.cpp 构建语音聊天机器人

大语言模型&#xff08;LLM&#xff09;为基于文本的对话提供了强大的能力。那么&#xff0c;能否进一步扩展&#xff0c;将其转化为语音对话的形式呢&#xff1f;本文将展示如何使用 Whisper 语音识别和 llama.cpp 构建一个 Web 端语音聊天机器人。 系统概览 如上图所示&…

网络地址转换

NAT概述 解决公有地址不足&#xff0c;并且分配不均匀的问题 公有地址&#xff1a;由专门的机构管理、分配&#xff0c;可以在因特网上直接通信 私有地址&#xff1a;组织和个人可以任意使用&#xff0c;只能在内网使用的IP地址 A、B、C类地址中各预留了一些私有IP地址 A&…

电脑无互联网连接怎么解决?分享5种解决方案

无互联网连接是指设备无法与互联网进行通信或连接失败。这可能会导致我们无法正常上网&#xff0c;给我们的日常生活和工作带来很大的不便。但请不要担心&#xff0c;下面将为您介绍一些解决无互联网连接问题的方法。 一、检查网络是否正常连接 首先&#xff0c;确保您的路由器…

使用 F5 TTS 文字转音频

F5 TTS 支持 ZeroShot 音频克隆&#xff0c;只有将需要音频传给模型&#xff0c;模型既可以生成以对应声音生成的音频&#xff0c;F5 最强大的地方就是可以使用定制的人声。F5 使用了 DIT 架构进行训练&#xff0c;结构如下&#xff1a; 本地使用 F5 TTS F5 使用很简单&#x…

【Redis】Redis 预备知识

目录 1. 基本全局命令 KEYS EXISTS DEL EXPIRE TTL TYPE 2. 数据结构和内部编码 3. 单线程架构 Redis 提供了5种数据结构&#xff0c;理解每种数据结构的特点对于 Redis 开发运维非常重要&#xff0c;同时掌握每种数据结构的常见命令&#xff0c;会在使用 Redis 的时…

【从零开始的LeetCode-算法】3304. 找出第 K 个字符 I

Alice 和 Bob 正在玩一个游戏。最初&#xff0c;Alice 有一个字符串 word "a"。 给定一个正整数 k。 现在 Bob 会要求 Alice 执行以下操作 无限次 : 将 word 中的每个字符 更改 为英文字母表中的 下一个 字符来生成一个新字符串&#xff0c;并将其 追加 到原始的…

软件设计模式复习

一、软件生存周期 二、软件开发过程模型 瀑布模型 特征&#xff1a; 从上一阶段承接的成果物作为本阶段的工作对象&#xff1b; 对上一阶段成果实施本阶段的活动&#xff1b; 给出本阶段的成果&#xff0c;作为下一阶段的输入&#xff1b; 对本阶段的工作进行评审&#xff0c…

搭建文件服务器并使用Qt实现文件上传和下载(带账号和密码)

文章目录 0 背景1 搭建文件服务器2 代码实现文件上传和下载2.1 在pro文件中添加网络支持2.2 创建网络管理类2.3 文件上传2.4 文件下载 3 扩展&#xff08;其他方法实现文件上传和下载&#xff09;3.1 python3.2 npm3.3 ftp服务器 4 完整的代码 0 背景 因为需要使程序具备在远程…

自动化运维(k8s)之微服务信息自动抓取:namespaceName、deploymentName等全解析

前言&#xff1a;公司云原生k8s二开工程师发了一串通用性命令用来查询以下数值&#xff0c;我想着能不能将这命令写成一个自动化脚本。 起初设计的 版本一&#xff1a;开头加一条环境变量&#xff0c;执行脚本后&#xff0c;提示输入&#xff1a;需要查询的命名空间&#xff0c…

springboot332基于springboot养老院管理系统pf(论文+源码)_kaic

毕 业 设 计&#xff08;论 文&#xff09; 养老院管理系统设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计…

js:函数

函数 函数&#xff1a;实现抽取封装&#xff0c;执行特定任务的代码块&#xff0c;方便复用 声明 函数命名规范 尽量小驼峰 前缀应该为动词&#xff0c;如getName、hasName 函数的调用 函数体是函数的构成部分 函数传参 参数列表里的参数叫形参&#xff0c;实际上写的数据叫实…

基于Matlab的图像去噪算法仿真

中值滤波的仿真 本节选用中值滤波法对含有高斯噪声和椒盐噪声的图像进行去噪&#xff0c;并用Matlab软件仿真。 &#xff08;1&#xff09;给图像加入均值为0&#xff0c;方差为0.02的高斯噪声&#xff0c;分别选择33模板、55模板和77模板进行去噪 Matlab部分代码&#xff1…

【Linux】-学习笔记06

第二章、时间同步服务器 2.1时间同步服务器的使用 2.1.1系统时区时间的管理 timedatectl set-time "2024-02-13 10:41:55" ##设定系统时间 timedatectl list-timezones ##显示系统的所有时区 timedatectl set-timezone "Asia/Shangh…

UE5_建立自己的资产库

资产库需要用到一个插件&#xff1a; UAsset Browser - 直接在当前项目预览其他UE项目资产&#xff08;.uasset 文件&#xff09; - 直接迁移其他UE项目资产到当前项目 - 不用另外打开资产项目查看资产&#xff0c;迁移资产&#xff08;麻烦&#xff09; 插件官网插件文档插…

详解登录MySQL时出现SSL connection error: unknown error number错误

目录 登录MySQL时出错SSL connection error: unknown error number 出错原因 使用MySQL自带的工具登录MySQL 登陆之后&#xff0c;使用如下命令进行查看 解决方法 找到MySQL8安装目录下的my.ini配置文件 记事本打开my.ini文件&#xff0c;然后按下图所示添加配置 此时再…

深度学习基本单元结构与输入输出维度解析

深度学习基本单元结构与输入输出维度解析 在深度学习领域&#xff0c;模型的设计和结构是理解其性能和应用的关键。本文将介绍深度学习中的基本单元结构&#xff0c;包括卷积神经网络&#xff08;CNN&#xff09;、反卷积&#xff08;转置卷积&#xff09;、循环神经网络&…

乐鑫发布 esp-iot-solution v2.0 版本

今天&#xff0c;乐鑫很高兴地宣布&#xff0c;esp-iot-solution v2.0 版本已经发布&#xff0c;release/v2.0 分支下的正式版本组件将为用户提供为期两年的 Bugfix 维护&#xff08;直到 2027.01.25 ESP-IDF v5.3 EOL&#xff09;。该版本将物联网开发中常用的功能进行了分类整…

面经-综合面/hr面

面经-综合面/hr面 概述1.大学期间遇到的困难&#xff0c;怎么解决的2. 大学期间印象最深/最难忘的是什么3. 大学里面担任了什么职务没&#xff1f;做了什么工作&#xff1f;4. 大学最大的遗憾是什么&#xff1f;5. 对自己的未来规划6. 对自己的评价7. 自己的优缺点8. 对公司的认…