linux的退出函数exit( )、_exit( )

1、void exit(int status);

该函数的功能是,使调用本函数的进程正常终止,然后把形参的值status&0377(八进制)返回给父进程,父进程可以通过wait“函数族”来获取这个返回值。

所有通过atexit( )和 on_exit( ) 注册的函数,会被挂在一个链表上,后注册的函数被挂在链表的最前面,当执行本函数exit()时,该链表上的函数会从头一个个的执行一遍(也即,按照注册的相反顺序)。这些注册的函数中如果也调用了atexit( )和 on_exit( ) 注册了一些函数的话,它们也会被执行。注意,如果注册的某个函数不返回(例如调用了强退函数_exit( ),又例如通过信号把自己kill掉),那么链表中该函数后面的那些函数就得不到执行了!尤其注意,标准流的清洗,也将无法被执行,可能造成文件不完整!如果一个函数被注册了N次,那么他将在链表中占据N个位置,被执行N遍。执行这个链表的过程,就类似于C++的析构过程。

形参:可选的值为EXIT_SUCCESS、EXIT_FAILURE。尽量不要用exit(0)、exit(1)等,linux建议使用宏来增强程序的可移植性。

返回值:不返回。

注意:如果注册的函数中调用了exit( )、longjmp( )的话,那么程序会出现不可预知的结果!如果本进程通过execve( )函数更换了实体,那么原先注册好的函数都将被移除。

exit(status)函数执行之后,形参的值会被传递到父进程,这时有3种情况:

① 如果父进程设置了SA_NOCLDWAIT标志,或者 把SIGCHLD信号的处理函数设置为SIG_IGN,那么子进程的返回值被丢弃;② 如果父进程在等待子进程,他将被通知子进程的退出状态;
以上两种情况,子进程都会立即消亡。

③ 如果父进程没有被设置为“忽略子进程的退出值”,这时父进程应当使用wait或者waitpid等待子进程的结束,如果父进程不等待,那么子进程结束之后会变成僵尸进程(只有一个单字节容器保存着子进程的退出值,其他什么都没有)。

如果父进程支持SIGCHLD信号,那么子进程结束后这个信号会被发到父进程。如果父进程设置了SA_NOCLDWAIT标志,那么SIGCHLD信号发或者不发,父进程都不会有任何动作。

如果本进程时一个会话的发起者(领导/头儿),且本进程的控制终端就是该会话的控制终端,那么该控制终端下的进程组中的每一个进程都会收到SIGHUP信号,并且,本进程的终端将会与该会话断开连接,该会话会允许自己被别的控制进程给捕获(连接)。

如果一个进程的退出,导致一个进程组变为孤立进程组,并且,如果该孤立进程组中的任何一个成员stop了,那么该进程组中的每一个进程都会收到两个连续的信号SIGCONT、SIGHUP。关于“孤立进程组”的相关概念,可参考man 2 setpgid命令。

2、 void _exit(int status);
void _Exit(int status);//等价于_exit

立即终止一个进程。任何被本进程打开的文件描述符都会被关闭;any children of the process are inherited by process 1, init,;该进程的父进程会收到SIGCHLD信号。

形参的值会被返回到父进程,该值被当做进程的退出状态,父进程可以通过wait函数族来捕获这个返回值。

注意:

本函数与上面的exit函数的区别是,本函数不会调用atexit( )、on_exit( )注册的函数。本函数是否要清洗标准流、是否要删除tmpfile函数创建的临时文件,这些问题不同平台的_exit函数的实现是不一样的。本函数不会关闭打开文件的描述符(这一点与上面的介绍矛盾,但是官方手册就是写的,我也不懂),这可能会导致未知的延迟,以等待挂起的输出彻底完成。如果你不想让程序发生这种延迟,那么你应该在执行本函数前,使用tcflush函数主动清洗流。在执行本函数时,到底是不是所有被挂起的IO都会被取消,到底哪一个被挂起的IO倍取消,这些问题不同平台的_exit函数的实现是不一样的。


猜你喜欢

转载自blog.csdn.net/qq_31073871/article/details/80926499