进程的退出

文章目录

1 进程的退出

在Linux系统中,进程终止(或者称为进程退出,为了统一,下文均使用”终止”一词)的常见方式有5种,可以分为正常终止与异常终止:

正常终止:

  • 从main函数返回。
  • 调用exit()函数终止。
  • 调用_exit()函数终止。

异常终止:

  • 调用abort()函数异常终止。
  • 由系统信号终止。

在Linux系统中,exit()函数定义在stdlib.h中,而_exit()定义在unistd.h中,exit()和_exit()函数都是用来终止进程的,当程序执行到exit()或_exit()函数时,进程会无条件地停止剩下的所有操作,清除包括 PCB在内的各种数据结构,并终止当前进程的运行。不过这两个函数还是有区别的。
在这里插入图片描述

从图中可以看出,_exit()函数的作用最为简单:直接通过系统调用使进程终止运行,当然,在终止进程的时候会清除这个进程使用的内存空间,并销毁它在内核中的各种数据结构;而exit()函数则在这些基础上做了一些包装,在执行退出之前加了若干道工序:比如exit()函数在调用exit系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,这就是”清除I/O缓冲”。

由于在 Linux 的标准函数库中,有一种被称作”缓冲 I/O(buffered I/O)”操作,其特征就是对应每一个打开的文件,在内存中都有一片缓冲区。每次读文件时,会连续读出若干条记录,这样在下次读文件时就可以直接从内存的缓冲区中读取;同样,每次写文件的时候,也仅仅是写入内存中的缓冲区,等满足了一定的条件(如达到一定数量或遇到特定字符等),再将缓冲区中的内容一次性写入文件。这种技术大大增加了文件读写的速度,但也为编程带来了一些麻烦。比如有些数据,认为已经被写入文件中,实际上因为没有满足特定的条件,它们还只是被保存在缓冲区内,这时用_exit()函数直接将进程关闭,缓冲区中的数据就会丢失。因此,若想保证数据的完整性,就一定要使用 exit()函数。

不管是那种退出方式,系统最终都会执行内核中的同一代码,这段代码用来关闭进程所用已打开的文件描述符,释放它所占用的内存和其他资源。

下面一起看看_exit()与exit()函数的使用方法:

头文件:

#include <unistd.h>
#include <stdlib.h>

函数原型:

void _exit(int status);
void exit(int status);

这两个函数都会传入一个参数status,这个参数表示的是进程终止时的状态码,0表示正常终止,其他非0值表示异常终止,一般都可以使用-1或者1表示,标准C里有EXIT_SUCCESS和EXIT_FAILURE两个宏,表示正常与异常终止。


参考资料:

  1. [野火]i.MX Linux开发实战指南
### 子进程退出机制与相关函数 在 Linux 系统中,子进程退出时,其资源不会立即被释放,而是进入“僵尸进程”状态,等待父进程通过特定的系统调用来回收其资源。若父进程未进行回收,子进程将一直保持僵尸状态,导致资源浪费。因此,理解子进程退出机制及对应的函数是进程编程的重要内容。 #### 子进程退出方式 子进程可以通过以下方式退出: 1. **正常退出**:通过调用 `exit()` 或 `_exit()` 函数,子进程可以正常终止,并返回一个退出状态码给父进程。 2. **异常退出**:通过接收到某些信号(如 `SIGKILL` 或 `SIGSEGV`)而异常终止。 其中,`exit()` 会刷新标准 I/O 缓冲区,而 `_exit()` 则不会,这可能导致缓冲区内容丢失 [^3]。 #### 相关函数 ##### 1. `wait()` 函数 父进程可以使用 `wait()` 函数来等待任意一个子进程结束,并回收其资源。该函数会阻塞父进程,直到某个子进程退出。 ```c #include <sys/wait.h> #include <unistd.h> #include <stdio.h> int main() { pid_t pid = fork(); if (pid > 0) { int status; pid_t child = wait(&status); if (WIFEXITED(status)) { printf("Child exited with code %d\n", WEXITSTATUS(status)); } } else if (pid == 0) { sleep(2); exit(50); } return 0; } ``` ##### 2. `waitpid()` 函数 与 `wait()` 不同,`waitpid()` 可以指定等待某个特定的子进程,并支持非阻塞方式(通过 `WNOHANG` 选项)。这种方式更灵活,适用于多子进程管理场景 [^1]。 ```c pid_t pid = waitpid(child_pid, &status, WNOHANG); if (pid == 0) { // 子进程尚未退出 } else if (pid > 0) { // 子进程退出 } ``` ##### 3. `vfork()` 函数 `vfork()` 也可以用于创建子进程,但其行为与 `fork()` 不同。它会阻塞父进程,直到子进程调用 `exec()` 或 `exit()`。因此,子进程在 `vfork()` 后应尽快调用这些函数,以避免资源占用 [^1]。 ##### 4. `WIFEXITED` 和 `WEXITSTATUS` 这些宏用于检查子进程是否正常退出,并获取其退出状态码。例如: ```c if (WIFEXITED(status)) { printf("Child exited with code %d\n", WEXITSTATUS(status)); } ``` ##### 5. `WIFSIGNALED` 和 `WTERMSIG` 这些宏用于判断子进程是否因信号而异常终止,并获取终止信号的编号 [^2]。 ```c if (WIFSIGNALED(status)) { printf("Child was killed by signal %d\n", WTERMSIG(status)); } ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值