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

【Linux系统】进程终止




在这里插入图片描述



一、进程退出方式


1、正常终止

主要两种类型:从 main 返回、调用 exit _exit

具体讲解如下:


(1)从 main 返回

这个的使用就不用多说了吧,相信你们已经烂熟于心了

  • 作用return 语句用于从函数中返回一个值,并终止该函数的执行。在 main 函数中,return 语句用于终止整个程序的执行,并返回一个状态码给操作系统。
  • 范围return 仅在函数内部有效,不能从全局作用域或其他地方使用。
  • 清理工作:在 main 函数中使用 return 时,会执行标准 I/O 缓冲区的刷新、关闭打开的文件描述符等清理工作,也会调用在 atexit 注册的函数。

执行 return x 等同于执行 exit(x),因为调用 main 的运行时函数会将 main 的返回值当做 exit 的参数。

exit 函数如何使用,看下文解释:



(2)调用 exit _exit

这两个系统调用函数可以立即终止整个程序的执行,但是他们两还是有不少区别的,这篇博客有更加详细的讲解:【Linux】 exit 和 _exit 的区别-CSDN博客


(3)returnexit 的异同点

作用范围

  • return :仅在函数内部有效,主要用于从函数中返回一个值。
  • exit_exit :可以在程序的任何地方调用,用于立即终止整个程序的执行。

清理工作

  • returnexit :都会执行标准 I/O 缓冲区的刷新、关闭打开的文件描述符等清理工作,并调用在 atexit 注册的函数。


2、异常终止


引入:ctrl + c

我们常常通过 ctrl + c 使当前正在执行的进程停下,其背后的原理是:

ctrl + c :信号终止,被强行杀掉

当用户在终端中按下 Ctrl+C 时,会向当前的前台进程发送 SIGINT(Interrupt)信号。这个信号通常用于中断或请求终止正在运行的程序。



正文如下

​ 进程因为异常而中断退出的情况通常是指由于某些内部错误或外部事件导致进程无法继续执行,从而被迫终止。OS提前使用信号终止你的进程,下面是几种常见的异常情况及其原因:

(1) 访问非法内存地址(Segmentation Fault)

即为 野指针 问题

当进程试图访问不允许访问的内存区域时,会触发 SIGSEGV 信号,导致进程被中断并退出。

示例代码
#include <stdio.h>
#include <stdlib.h>int main() {int *ptr = NULL;*ptr = 42;  // 尝试访问空指针指向的内存return 0;
}


(2) 除零错误(Division by Zero)

当进程执行除法运算时除数为零,会触发 SIGFPE 信号,导致进程被中断并退出。

示例代码
#include <stdio.h>
#include <stdlib.h>int main() {int result = 1 / 0;  // 除零错误return 0;
}


(3)系统调用失败

当进程执行某些系统调用时发生错误,可能会导致进程异常退出。例如,打开文件失败、创建文件失败等情况。

示例代码
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>int main() {int fd = open("nonexistent_file.txt", O_RDONLY);if (fd == -1) {perror("open");return EXIT_FAILURE;}close(fd);return 0;
}


(4)文件权限问题

当进程试图访问没有权限访问的文件时,会触发 SIGBUSSIGSEGV 信号,导致进程被中断并退出。

示例代码
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>int main() {int fd = open("/root/protected_file.txt", O_RDONLY);if (fd == -1) {perror("open");return EXIT_FAILURE;}close(fd);return 0;
}


(5) 进程被杀死

当进程被其他进程或管理员使用 kill 命令发送 SIGKILL 信号时,进程会被强制终止,而不会执行任何清理工作。

示例命令
kill -9 <PID>


总结

进程因为异常而中断退出的情况包括但不限于:

  • 访问非法内存地址(野指针):尝试访问不允许访问的内存区域,触发 SIGSEGV 信号。
  • 除零错误:执行除法运算时除数为零,触发 SIGFPE 信号。
  • 系统调用失败:执行某些系统调用时发生错误,导致进程异常退出。
  • 文件权限问题:试图访问没有权限访问的文件,触发 SIGBUSSIGSEGV 信号。
  • 进程被杀死:被其他进程或管理员使用 SIGKILL 信号强制终止。

了解这些异常情况及其原因有助于更好地调试和优化程序,确保进程能够在各种环境下稳定运行。



二、进程退出码的获取

1、退出状态码的作用

前面讲解过,无论是通过 return exit/_exit 正常退出,还是被信号终止或停止的异常退出,进程退出都会返回一个退出状态码给父进程,用于告知父进程:我这个退出的子进程是否正确执行任务,如果是异常退出,我又是因为什么原因退出的。

这个状态码包含了关于子进程退出原因的重要信息,父进程可以通过解析这个状态码来了解子进程的退出情况。




2、退出状态码是 16 位的整数

在 Unix 和 Linux 系统中,退出状态码通常是一个 16 位的整数,其中高 8 位和低 8 位分别包含不同的信息:

  • 低 8 位:表示子进程的退出状态码(0-255)。对于正常退出,这是 returnexit 传递的值。
  • 高 8 位:包含其他信息,如终止信号编号等。

如下图的两行长方形,代表着两种进程退出时退出状态码的各个部分的作用:正常终止、被信号所杀

在这里插入图片描述




3、进程退出码的来源

当子进程终止时,操作系统会记录子进程的退出状态码,并将其保存在子进程的进程控制块(PCB)中。

父进程调用 waitwaitpid 时,操作系统会将子进程的退出状态码返回给父进程。

进程退出码并不是通过我们下面几条程序代码函数返回的,而是操作系统负责返回的,

我们下面几条程序要做的是设置与修改进程退出状态码,而不负责退出码返回。



(1)子进程正常退出:

当进程正常退出时,操作系统会设置退出状态码为 returnexit/_exit 传递的值。

  • main 函数 return status 返回:默认返回值为 0(表示成功退出)
  • exit(int status) 返回
  • _exit(int status) 返回

(一个进程只要是通过 exit 或 _exit函数直接退出的,就算做正常退出!)



(2)子进程异常退出:

当进程因接收到信号而终止时,操作系统会设置退出状态码的高 8 位为信号编号,低 8 位通常为 0。



4、如何获取进程退出码

而我们可以通过一些系统宏定义来获取进程的退出状态码,本篇博客中有这些宏定义的使用与使用示例:【Linux】如何通过系统宏定义,获取进程的退出码或退出信号-CSDN博客


http://www.mrgr.cn/news/59081.html

相关文章:

  • 攻防靶场(22):SO SIMPLE
  • CSS-层叠性质
  • NLP库——Spacy库教程
  • 【Unity 安装教程】
  • docker搭建mysql多主多从环境
  • 000010 - Mapreduce框架原理
  • Elasticsearch安装使用
  • Python数值计算(33)——simpson 3/8积分公式
  • 011 操作符详解 中
  • 硬件设计-PCIe时钟抖动测量
  • Oracle故障诊断(一线DBA必备技能)之ADRCI(二)
  • 【华为\荣耀、中兴、华三路由器IPV6设置】
  • 淘知学堂 1.0.0 | 不收费的英语启蒙软件,涵盖小中高
  • 【智能大数据分析 | 实验四】Spark实验:Spark Streaming
  • 开源生活-分布式管理
  • 《面试最爱问的Spring》- IOC启动流程,底层实现、配置方式详解
  • 传奇996_5——使用补丁制作武器
  • 代码随想录第十一天|150. 逆波兰表达式求值、239. 滑动窗口最大值、347.前 K 个高频元素
  • qml圆形图片,qml圆形头像制作
  • 家人们,做小红书/小绿书一定要学会蹭热点啊
  • 移植picocom到hisi平台上
  • PDF怎么编辑修改内容?这份PDF编辑器全攻略请收好!
  • 清理pip和conda缓存
  • linux驱动_platform总线是如何注册的
  • Android——事件冲突处理
  • springboot083基于springboot的个人理财系统--论文pf(论文+源码)_kaic