Linux - 进程 - 进程终止

一. 进程退出场景

  • 进程正常终止, 结果正确.

  • 进程正常终止, 结果不正确.

  • 进程异常终止.

二. 进程正常终止

从 main 返回

C 程序总是从 main 函数开始执行, main 函数的原型是:

但实际上 main 函数只是用户程序的入口, 当内核执行 C 程序时(使用一个 exec 函数), 在调用 main 前先调用一个特殊的启动例程. 可执行程序文件将此启动例程指定为程序的起始地址. 启动例程从内核取得命令行参数和环境变量值, 然后为按上述方式调用 main 函数做好准备.

从 main 函数 return 是一种常见的进程终止方法. 启动例程使得 main 返回后立即调用 exit(), 在 main 中执行 return n 等同于执行 exit(n), 因为调用 main 的启动例程会将 main 的返回值当做 exit() 的 status 参数. 如果将启动例程以 C 代码形式表示 (实际上该例程常常用汇编语言编写), 则它调用 main 函数的形式可能是:

通过如下一段代码对上述描述进行验证.

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    printf("hello world\n");
    return 0;
}

当运行生成的可执行程序后, 使用 echo $? 打印最近一次进程的退出码, 为 0, 说明该进程确实正常终止了. 在 Linux 中, 0 通常表示成功, 非 0 值表示失败.

进程退出码

C 库中的 strerror 可以通过错误码, 获取对应的错误信息.

c 复制代码
#include <stdio.h>
#include <string.h>

int main()
{
    int i = 0;
    for ( ; i < 134; i++) {
        printf("%d:%s\n", i, strerror(i));
    }
    return 0;
}

当运行生成的可执行程序后, 就可以看到各个错误码所对应的错误信息.

注意: 退出码都有对应的错误信息, 帮助用户确认程序执行失败的原因, 而这些退出码具体代表什么含义是人为规定的, 不同环境下相同的退出码的错误信息可能不同.

_exit()

_exit() 会直接终止进程, 并不会在退出进程前会做任何收尾工作.

c 复制代码
#include <stdio.h>
#include <unistd.h>

int main()
{
    printf("hello world");
    _exit(1);
}

以上代码中使用 _exit() 终止进程, 缓冲区当中的数据将不会被打印到显示屏上.

exit()

使用 exit() 终止进程是常用的方法, exit() 可以在任何地方终止进程, 并在终止进程之前会做一系列工作:

  1. 调用任何由 atexit() 或 on_exit() 注册的函数, 和在系统中注册时顺序相反.

  2. 清空并关闭所有已经打开的标准 I/O 流 (此过程将所有被缓冲但还没有被写出的数据写出).

  3. 删除由 tmpfile() 函数创建的所有临时文件.

这些步骤完成了在用户空间需要做的所有工作, 最后 exit() 会调用系统调用 _exit(), 内核可以处理终止进程的剩余工作.

对以下代码进行测试.

c 复制代码
#include <stdio.h>
#include <stdlib.h>

int main()
{
    printf("hello world");
    exit(2);
}

运行结果如下.

三. 进程异常终止

进程一般由于接到一个信号而异常终止, 后期谈论进程信号时再谈论这一话题.

四. exit() 与 _exit() 中的 status

对如下一段代码进行测试.

c 复制代码
#include <stdio.h>
#include <stdlib.h>

int main()
{
    exit(-1);
    return 0;
}

当运行生成的可执行程序后, 使用 echo $? 打印最近一次进程的退出码, 发现其为 255, 而非 -1.

出现这样的现象, 是因为父进程通过 wait() 来获取子进程的退出码 时 status 仅有低 8 位可以被父进程所用.

以上面那一段代码为样例进行说明: 对于无符号整型来说, 数据以补码的形式存放在内存中, 所以 status 的二进制表示为 11111111 11111111 11111111 11111111, 而 0377 的二进制表示为 11111111, 两者按位与的结果即为 11111111, 表示为十进制即为 255, 所以使用 echo $? 打印最近一次进程的退出码, 其值为 255, 而非 -1.

相关推荐
人工智能训练师1 小时前
Ubuntu22.04如何安装新版本的Node.js和npm
linux·运维·前端·人工智能·ubuntu·npm·node.js
灿烂阳光g1 小时前
domain_auto_trans,source_domain,untrusted_app
android·linux
Ronin3053 小时前
【Linux系统】日志与策略模式
linux·策略模式·日志
ZzzK,3 小时前
JAVA虚拟机(JVM)
java·linux·jvm
Aspiresky4 小时前
浅析Linux进程信号处理机制:基本原理及应用
linux·运维·信号处理
ajassi20005 小时前
linux C 语言开发 (八) 进程基础
linux·运维·服务器
..过云雨5 小时前
05.【Linux系统编程】进程(冯诺依曼体系结构、进程概念、进程状态(注意僵尸和孤儿)、进程优先级、进程切换和调度)
linux·笔记·学习
matlab的学徒6 小时前
Web与Nginx网站服务(改)
linux·运维·前端·nginx·tomcat
Insist7536 小时前
prometheus安装部署与alertmanager邮箱告警
linux·运维·grafana·prometheus
BAGAE6 小时前
MODBUS 通信协议详细介绍
linux·嵌入式硬件·物联网·硬件架构·iot·嵌入式实时数据库·rtdbs