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

【Linux手册】进程终止:进程退出和信号的响应机制

文章目录

  • 前言
  • 进程退出的场景
    • 退出码
    • errno
  • 代码异常终止
  • exit和_exit

前言

进程最终都会终止,进程终止本质上就是进程资源的释放,回收。本文侧重于进程终止的方式,以及自己编写代码时让进程终止的方法。

进程退出的场景

进程退出一共分为三种:

  • 进程运行完毕,结果正确。这是我们最希望的情况;
  • 进程运行完毕,结果不正确;
  • 进程异常结束。

退出码

进程运行结束就是main函数调用完毕了,可以根据main函数的返回值来判断进程运行的情况。一般情况下在main中return 0表示程序正常结束,不同的退出码可以代表不同的含义,这样就能将进程的运行结果返回出来了。

如何查看不同的退出码对应的信息???

在C语言中有char* strerror(int i) 函数可以查看不同的退出码的含义;
在这里插入图片描述

通过以上代码可以显示不同的返回值代表的含义,当然如果你觉得这些退出与信息的设定并不是自己希望的,你也可以自己设计一套错误表示,必定是我们自己在进行编码return值嘛。

进程的退出码最终应该被父进程拿到,因为父进程才是最关心当前进程的"人"。我们知道在命令行上创建的所有进程都是bash的子进程。可以通过echo $? 的方式来获刚刚运行的子进程退出码。
在这里插入图片描述

根据上图可以看到我故意将程序的退出码设置为11,通过echo $?也确实看到了上一个进程的退出码是11.

但是如果再次使用echo $?就会发现,退出码变成了0,这是为什么???

退出码变成了0说明这个退出码就不是./test.eve的退出码,那它肯定就是echo的退出码,每一条指令都是一个可执行程序,那指令有退出码也很正常。

当使用fork创建子进程的时候,父进程又如何获取到子进程的退出码呢???

父进程需要通过进程等待的方式来获取子进程的退出码以及相关信息,关于进程等待相关知识后面会专门开一个专题讲解

errno

在调用一些库函数的时候,有可能会出现库函数调用失败的情况,errno会存储最近一次库函数调用失败的返回码。

比如下面调用malloc如果开辟空间失败,可以将errno存储到ret中进行返回,来告诉父进程malloc开辟空间失败。
在这里插入图片描述

因为errno存储的是最近一次库函数调用时出错的返回码,如果一个程序中又多个位置库函数调用失败,就会导致错误码被覆盖,所以要及时对errno中的值进行检查。

代码异常终止

代码异常终止的情况在日常编码中也是很常见的,比如除0操作,数组越界…

对于异常终止的程序退出码是没有意义的 ,异常终止可能代码根本没有跑完,就算是运行完了,其退出码也可能因为异常情况而发生改变。

因为异常终止的情况所以当一个进程结束时,先看代码是否异常,再看退出码
在Linux中可以通过 kill -l 的方式查看各种异常信息,当然这些信号都是一些缩写。
在这里插入图片描述

当程序出现异常的时候,异常会转化为信号的方式发送给进程,从而让进程直接退出。 当然我们也可以在bash命令行上对进程发送信号,其中我们比较熟的有:kill -9 PID杀死一个进程,kill -19 PID将进程暂停。

exit和_exit

void exit(int state)在我们编写代码中比较常见,就是直接将进程终止,并返回退出码。

exit在任意一个位置调用,进程都会直接终止,不会再执行后面代码了。

void _exit(int state) 是一个系统调用接口,那它与exit有什么区别呢?通过以下两段代码看看。

在这里插入图片描述

在这里插入图片描述

在使用exit()的程序中打印出来"hello Linux",而使用的_exit()中并没有打印出任何东西,通过这个现象说明两者确实是不一样的。

在上面代码打印中没有使用\n或者其他刷新缓冲区的操作,程序就直接退出了。而两个接口不同之处就在于是否打印出信息。
所以exit()和_exit()的主要区别在于是否会刷新缓冲区 很显然_exit()没有刷新缓冲区,exit()刷新了缓冲区。

_exit()是系统调用接口,是操作系统提供的一个接口,而exit()是库函数,是程序员对系统调用接口进行封装后提供给我们的接口。实际上exit()中调用了_exit()接口,只不过在调用该接口之前对缓冲区进行了刷新。
在这里插入图片描述

通过exit()和_exit()调用的区别也可以猜测,缓冲区一定不在内存中的操作系统内核区域,而是在用户区,因为操作系统不会做浪费空间和资源的行为,如果缓存在操作系统中一定会进行刷新,如果不刷新操作系统不就浪费空间了嘛。

http://www.lryc.cn/news/576112.html

相关文章:

  • VB.NET,C#字典对象来保存用户数据,支持大小写
  • Selenium 多窗口截图(窗口切换)二次封装方法详解 —— Python 实践
  • 【Python】实现对LGBT+ rights worldwide (2025)数据集的可视化展示
  • MySQL在C中常用的API接口
  • TiDB AUTO_RANDOM 超大主键前端精度丢失排查:JavaScript Number 限制与解决方案
  • 玩转Linux CAN/CAN FD—SocketCAN的使用
  • opensuse安装rabbitmq
  • 【编译原理】期末复习知识总结
  • 【大数据】大数据产品基础篇
  • 【开源项目】「安卓原生3D开源渲染引擎」:Sceneform‑EQR
  • ArcGIS Pro利用擦除工具,矢量要素消除另一矢量部分区域
  • 【网络安全】密码学知识普及
  • 高可用与低成本兼得:全面解析 TDengine 时序数据库双活与双副本
  • OkHttp 简单配置
  • pandas---使用教程
  • 解构SAP RISE与Cloud ERP授权新政:从许可模式到迁移策略的深度指南
  • (一)miniconda安装配置
  • Dubbo服务调用超时问题解决方案
  • Hyperledger Fabric 入门笔记(二十)Fabric V2.5 测试网络进阶之Tape性能测试
  • Linux tcp_info:监控TCP连接的秘密武器
  • 【RAG面试题】如何获取准确的语义表示
  • MCP-安全(代码实例)
  • ubuntu安装达梦数据库
  • Java8方法引用:简洁高效的编程利器
  • algorithm ——————》双指针(移动0 复写0 快乐数 装水问题 以及数组中找几个数和为指定的元组)
  • TCP四层模型:网络协议核心解密
  • WPF 3D 开发全攻略:实现3D模型创建、旋转、平移、缩放
  • HTTP协议中Connection: Keep-Alive和Keep-Alive: timeout=60, max=100的作用
  • Linux入门攻坚——49、高可用HA之corosync/pacemaker(2)
  • Linux命令行操作基础