我们知道做什么事情都是有始有终,在编程中也是一样。在Linux中创建一个进程后,程序的末尾我们要将其退出,在Linux中进程退出总共有八种方法,本篇文章主要讲解其中两个函数。
调用格式
#include<stdio.h>
#include<unistd.h>
void exit(int status);
void _exit(int status);
exit系列函数并没有返回值,它使用一个叫做终止状态的整型变量作为参数,内核会对这个终止状态进行检查,异常终止时,内核会直接产生一个终止状态字,描述异常终止的原因。对于终止状态字,我们可以调用wait或者waitpid函数来获取,有兴趣的小伙伴可以翻阅相关资料。
调用过程
调用过程如图所示,从图中可以看出:
- _exit函数直接使进程停止,清除其使用的内存空间,和内核中的各种数据结构
- exit函数在_exit的基础上进行了包装,加了好几道工序。
差别
exit函数在调用之前要检查文件的打开情况,在这个过程中会把缓冲区中的数据写入文件。_exit函数做事就比较果断,直接使进程终结。
这里讲点题外话:缓冲I/O
在Linux标准库中有中叫做缓冲I/O的操作,它的作用就是对应每一个打开的文件,都会在内存中存在一个缓冲区。每次读文件时,会读出若干条记录,方便下次读取。写文件也是同样的情况,先写到缓冲区,然后等满足一定条件,再将缓冲区中的数据写入文件。这种技术提高了文件读写的速度,但是也带来一些弊端。有时候你认为程序已经将数据写入文件,其实不然,所以有可能造成数据丢失。为了避免这种情况的发生,对于退出函数的理解就很重要了。
先看一段代码
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
int main (int argc,char * argv[])
{
pid_t pid;
pid = fork();
if(pid < 0)
{
printf("进程创建失败\n");
return 0;
}
else if(pid == 0)
{
printf("子进程\n");
printf("程序员真帅");
exit(0);
}
else
{
sleep(3);
printf("父进程\n");
printf("程序员真棒");
_exit(0);
}
return 0;
}
printf函数通过换行符来刷新字符串,因没有换行符,所以程序员的美誉之词并不会输出,调用exit函数将文件内容从缓冲区写入文件,所以在终端上我们可以看到子进程的两条输出语句。相应的_exit函数直接将缓冲区中的数据丢掉,我们只能看见父进程中第一条带有换行符的输出语句
输出结果:
正好验证了我们的猜测。
文章难免会有所疏漏和考虑不全的地方,如果有问题,欢迎指正哦。