编写背后:视频采集应用程序的main函数中atexit(&free_dev)的调用
基础理解:
函数名: atexit
头文件:#include<stdlib.h>
功 能: 注册终止函数(即main执行结束后调用的函数)
用 法: int atexit(void (*func)(void));
注意:按照ISO C的规定,一个进程可以登记多达32个函数,这些函数将由exit自动调用。atexit()注册的函数类型应为不接受任何参数的void函数,exit调用这些注册函数的顺序与它们登记时候的顺序相反。同一个函数如若登记多次,则也会被调用多次。
程序例:
#include <stdio.h>
#include <stdlib.h>
void exit_fn1(void)
{
printf("Exit function #1 called\n");
}
void exit_fn2(void)
{
printf("Exit function #2 called\n");
}
int main(void)
{
/* post exit function #1 */
atexit(exit_fn1);
/* post exit function #2 */
atexit(exit_fn2);
return 0;
}
输出:
Exit function #2 called
Exit function #1 called
进程的终止方式:
有8种方式使进程终止,其中前5种为正常终止,它们是
1:从 main 返回
2:调用 exit
3:调用 _exit 或 _Exit
4:最后一个线程从其启动例程返回
5:最后一个线程调用 pthread_exit
异常终止有3种,它们是
6:调用 abort
7:接到一个信号并终止
8:最后一个线程对取消请求做出响应
#include <stdlib.h?
void exit (int status);
void _Exit (int status);
#include <unistd.h>
void _exit (status);
其中调用 _exit,_Exit 都不会调用终止程序
异常终止也不会。
对比+例程---加深理解
对比atexit 、 exit、 _exit、 ptread_exit
关于atexit()函数:
main 函数执行完后,如果需要再执行一段代码的话可以调用atexit()注册一个函数:例如:
#include<stdio.h>
#include<stdlib.h>
void fumc1()
{printf("next\n");}
void fumc2()
{printf("executed");}
void fumc3()
{printf("is");}
void fumc4()
{printf("this");}
void main()
{
char str[]="0123456789";
atexit(fumc1);
atexit(fumc2);
atexit(fumc3);
atexit(fumc4);
printf("%d\n",sizeof(str));
printf("main execued to the end. \n");
}
执行结果:
main execued to the end.
11
thisisexecutednext
本来到该结束程序printf("main execued to the end. \n");
但是还打印thisisexecutednext
说明:mian程序结束后,还运行atexit函数
关于exit、 _exit、 ptread_exit的区分:
(1)终止”进程” 调用:exit和_exit
注意:如果进程中任何一个线程中调用exit或_exit,那么整个进程都会终止。(会导致线程退出)
(2)终止“线程”调用:ptread_exit
而“线程”的正常退出方式3种:
A线程从启动例程中返回(return())
B线程可以被另一个进程终止
C线程自己调用pthread_exit函数
关于exit、 _exit 的区分
_exit()函数:的作用最为简单:直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构;
exit() 函数:则在这些基础上作了一些包装,在执行退出之前加了若干道工序,也是因为这个原因,有些人认为exit已经不能算是纯粹的系统调用。
exit()函数与_exit()函数最大的区别就在于exit()函数在调用exit系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,就是"清理I/O缓冲"。
在Linux的标准函数库中,有一套称作"高级I/O"的函数,我们熟知的printf()、fopen()、fread()、fwrite()都在此 列,它们也被称作"缓冲I/O(buffered I/O)",其特征是对应每一个打开的文件,在内存中都有一片缓冲区,每次读文件时,会多读出若干条记录,这样下次读文件时就可以直接从内存的缓冲区中读取,每次写文件的时候,也仅仅是写入内存中的缓冲区,等满足了一定的条件(达到一定数量,或遇到特定字符,如换行符和文件结束符EOF),再将缓冲区中的 内容一次性写入文件,这样就大大增加了文件读写的速度,但也为我们编程带来了一点点麻烦。如果有一些数据,我们认为已经写入了文件,实际上因为没有满足特定的条件,它们还只是保存在缓冲区内,这时我们用_exit()函数直接将进程关闭,缓冲区中的数据就会丢失,反之,如果想保证数据的完整性,就一定要使用exit()函数。
下面我们来看两小段程序并对比起输出结果:
程序一:
#i nclude<stdlib.h>
main()
{
printf(" if i will be output ?");
printf(" if i will be in the buffer?");
exit(0);
}
输出结果:
if i will be output ?if i will be in the buffer?
(如图:为编译和执行结果)
程序二:
#include<unistd.h>
main()
{
printf(" if i will be output ?");
printf(" if i will be in the buffer?");
_exit(0);
}
输出结果:
(没有任何输出)
对比上面两个结果,我们可以更好的理解上面提到过的这两句关键的文字
1.exit()函数与_exit()函数最大的区别就在于exit()函数在调用exit系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,就是"清理I/O缓冲"。
2.有一些数据,我们认为已经写入了文件,实际上因为没有满足特定的条件,它们还只是保存在缓冲区内,这时我们用_exit()函数直接将进程关闭,缓冲区中的数据就会丢失,反之,如果想保证数据的完整性,就一定要使用exit()函数。
附:如果读者对缓冲机制不太理解可以参见我博客里的另一篇博文《UNIX里关于标准IO的几种缓冲机制》,它可以帮助你更好的理解本文中关于exit和_exit()的区别。