索引
[说明]:内容总结自APUE第7章进程环境及第8章进程控制。
进程终止
进程的终止方式分为正常终止与异常终止两种。其中正常终止方式有5种,异常终止方式有3种。
正常终止
- 从main返回。
- 调用exit。
- 调用_exit或_Exit。
- 最后一个线程从其启动例程返回。
- 最后一个线程调用pthread_exit。
异常终止
- 调用abort。
- 接到一个信号并终止。
- 最后一个线程对取消请求做出响应。
exit函数
函数原型及所在头文件:
#include <stdlib.h>
void exit(int status);
void _Exit(int status);
#include <unistd.h>
void _exit(int status);
使用不同头文件的原因是:exit和_Exit是由ISO C说明的,而_exit则是由POSIX.1说明的。
_exit和_Exit立即进入内核,exit则先执行一些清理处理(包括调用执行各终止处理程序,关闭所有标准I/O流等),然后进入内核。
exit
exit函数由ISO C定义,其操作包括:
调用各终止处理程序(终止处理程序在调用atexit函数时登记);
然后执行一个标准I/O库的清理关闭操作:为所有打开流调用fclose函数,这会造成所有缓冲的输出数据都被冲洗(写到文件上)。
因为ISO C并不处理文件描述符、多进程(父、子进程)以及作业控制,所以这一定义对UNIX系统而言是不完整的。
main函数返回一整型值与用该值调用exit是等价的。即在main函数中
exit(0);
等价于
return 0;
_exit _Exit
ISO C定义_Exit,其目的是为进程提供一种无需运行终止处理程序或信号处理程序而终止的方法。
对标准I/O流是否进行冲流,这取决于实现。在UNIX系统中,_Exit和_exit是同义的,并不清洗标准I/O。
_exit函数由exit调用,它处理UNIX特定的细节。
测试exit _exit _Exit
下面分别对这三个函数进行简单的测试。
测试exit
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE * fp = fopen("./test", "w");
if (fp)
{
fputs("hello world", fp);
exit(1); // 直接调用exit,特意不调用fclose
}
return 0;
}
编译完成后,执行程序,先看一下程序返回的状态码:
可以看到,状态码为1,即程序执行到exit(1);之后,就结束了。接下来看一下文件test中是否写入了相关内容。
可以看到,”hello world”成功的写入了文件中,即说明exit()函数冲洗了标准I/O。
测试_Exit
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE * fp = fopen("./test", "w");
if (fp)
{
fputs("hello world", fp);
_Exit(2);
}
return 0;
}
下面来看一下效果
可以看到,调用_Exit,并没有冲洗标准I/O。
测试_exit
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE * fp = fopen("./test", "w");
if (fp)
{
fputs("hello world", fp);
_exit(3);
}
return 0;
}
我们通过下面的运行结果可以看出,调用_exit和调用_Exit的效果是一样的,均没有冲洗标准I/O。