进程的终止方式
1. 终止类别
正常终止
- 从main函数返回
- 调用exit(标准c库函数)
- 调用_exit或者_Exit(系统调用)
- 最后一个线程从其启动例程(进程)返回
- 启动例程会搜集命令行参数给main传参,并搜集环境信息构建环境表给main函数,还会登记进程的终止函数
- 在进程的main函数执行前内核会启动
- 编译器在编译时会将启动例程编译进可执行文件中
- 最后一个线程调用pthread_exit
异常终止
- 调用abort
- 接收到一个信号并终止
- 最后一个线程对取消请求做处理响应
进程返回
- 通常进程运行成功返回0,否则返回非0
- 在shell中可以查看进程的返回值(echo $?)
2. 自定义终止函数
atexit函数
- 原型:
int atexit(void (*function) (void));
- 返回:成功返回0,出错返回-1
- 功能:向内核登记终止函数
- 注意:
- 每个启动的进程都默认的登记了一个标准的终止函数
- 终止函数在进程终止时释放进程所占用的一些资源
- 登记的多个终止函数的执行顺序是以栈的方式进行,即先登记后执行
- 原型:
示例:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
//定义进程的终止函数
void term_fun1(void){
printf("first term fucntion\n");
}
void term_fun2(void){
printf("second term fucntion\n");
}
void term_fun3(void){
printf("third term fucntion\n");
}
int main(int argc, char *argv[]){
if(argc < 3){
fprintf(stderr, "usage: %s file [exit|_exit|return]\n", argv[0]);
exit(1);
}
//向内核登记终止函数
atexit(term_fun1);
atexit(term_fun2);
atexit(term_fun3);
FILE *fp = fopen(argv[1], "w");
fprintf(fp, "hello iotek"); //全缓存函数
if(!strcmp(argv[2], "exit")){
exit(0);
}
else if(!strcmp(argv[2], "_exit")){
_exit(0);
}
else if(!strcmp(argv[2], "return")){
return 0;
}
else{
fprintf(stderr, "usage: %s file [exit|_exit|return]\n", argv[0]);
}
}
运行测试
return
- 说明:前面说过终止函数的方式是以栈的方式进行,所以看到3,2,1的顺序
exit
- 说明:前面说过终止函数的方式是以栈的方式进行,所以看到3,2,1的顺序,和return不同的是只释放一次资源
_exit(_Exit)
- 说明:在调用的时候,因为fprintf是c语言的带缓冲的库函数,所以存放数据是先存放在自己的缓冲区,等待写满,但是在这之前调用_exit函数导致没有清缓存,最终文件里面也没有数据
3. 总结
return | exit | _exit (_Exit) | |
---|---|---|---|
是否刷新标准I/O缓存 | 是 | 是 | 否 |
是否自动调用终止函数 | 是 | 是 | 否 |
- 注意:在网络编程时,调用return几次,就释放几次内核资源,调用exit多次,只释放一次。