如果在UNIX或Linux系统下使用C/C语言编程,应该会遇到很多进程退出相关函数的情况。有的是C标准库提供的函数,有的是系统调用,有的是某个系统特有的系统调用或函数,名字非常相似,给人眼花缭乱的感觉。
本文试图总结一些常见的系统调用和函数,并通过一个例子展示基本用法。
进程退出系列系统调用/function _exit_exit(2)属于POSIX系统调用,适用于UNIX和Linux系统。调用这个系统调用会导致当前进程直接退出,函数不会返回。内核将关闭这个进程打开的文件描述符。如果有子进程,会被1号进程采用,然后向该进程的父进程发送SIGCHLD信号。
功能原型如下:
# include unistd . hnoreturn void _ exit(int status);参数列表
“状态”3360过程退出代码
返回值
没有返回值
Exit_groupexit_group(2)是Linux系统特有的系统调用,会导致进程的所有线程退出。从glibc 2.3开始,_exit实际上是exit_group系统调用的包装器。因此,它们在Linux系统上是等效的。
功能原型如下:
# include Linux/unistd . hvoid exit _ group(int status);参数列表
“状态”3360过程退出代码
返回值
没有返回值
_Exit_Exit(3)是一个C标准库函数,功能上等同于_Exit系统调用,由C99引入。因为是标准库提供的函数,所以在跨平台可移植性上比_exit要好,建议先用。
功能原型如下:
# include stdlib . h void _ Exit(int status);参数列表
“状态”3360过程退出代码
返回值
没有返回值
Exit (3)是C标准库函数,也是最常用的进程退出函数。它与_exit和_Exit的区别在于,除了使进程退出的核心功能(也是通过调用_exit系统调用来实现)之外,它还执行一些前置动作:
执行逐个注册的自定义清理函数(由atexit或on_exit函数注册)刷新标准I/O流缓冲区,关闭并删除标准库函数tmpfile创建的临时文件。原型功能如下:
# include stdlib . hnoreturn void exit(int status);参数列表
“状态”3360过程退出代码
返回值
没有返回值
Atetitexit (3)是一个C标准库函数,用于注册进程出口清理函数。该功能在使用时有以下注意事项:
清洗功能的执行顺序与登记顺序相反。当进程收到致命信号时,将不会执行注册的清洗功能。当进程调用_exit(或_Exit)时,注册的清理函数将不会被执行。执行清洗功能时,如果收到致命信号或在清洗功能中调用_exit(或_Exit ),清洗功能将不会返回,其他后续清洗功能将被放弃。当同一清洗功能被多次注册时,正常情况下清洗功能将被执行相应的次数。如果父进程在调用fork之前注册了清理函数,这些清理函数也会被子进程继承;如果子进程随后调用exec系列函数,子进程继承的清洗函数将被删除。单个进程可以注册的清洗功能的数量不会少于32。功能原型如下:
# include stdlib . hint at exit(void(* function)(void));参数列表
‘function’3360用户定义的程序退出清洗功能。
返回值
成功返回0,非零值表示失败。
On_exit在功能上类似于atexit函数,也有on_exit(3)函数。它是Linux系统中特有的函数,用来注册进程退出清理函数。与atexit函数不同,它支持附加参数。
功能原型如下:
# include stdlib . hint on _ exit(void(* function)(int,void *),void * arg);参数列表
‘function’3360用户定义的程序退出清洗功能。
类型为 arg` :` void * 的自定义参数。
返回值
成功返回0,非零值表示失败。
example # includesstdio . h # includesstdlib . h # includestring . h # includesunistd . h void clean up 1(){ fprintf(stderr,[1]clean up \ n );睡眠(1);}void cleanup2() { fprintf(stderr,
"[2]cleanup\n"); sleep(1);}void cleanup3(int status, void *arg) { fprintf(stderr, "[3]cleanup: %s\n", (char *)arg); sleep(1);}int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Usage: %s exit
_exit
_Exit
return\n", argv[0]); return EXIT_FAILURE; } // atexit注册自定义清理函数 atexit(cleanup1); atexit(cleanup2); atexit(cleanup2); // 多次注册同一个函数 // 非标准函数on_exit,仅Linux下有效 // on_exit(cleanup3, (void *)"bye!!!"); // on_exit(cleanup3, (void *)"bye!!!"); // 多次注册同一个函数 fprintf(stdout, "a newline!\n"); // 向stdout写入带换行符的字符串(行缓冲,遇到换行符的情况下就会调用write系统调用输出内容) fprintf(stderr, "[stderr]a newline!"); // 向stderr写入不带换行符的字符串(stderr默认情况下无缓冲,直接调用write系统调用) fprintf(stdout, "[stdout]forgot a newline!"); // 向stdout写入不带换行符的字符串(若不刷新缓冲区,则该行内容不会被输出) if (strcmp("exit", argv[1]) == 0) { // 作用:执行一些前置的清理操作并终止当前进程 // 标准库函数(C89) // #include <stdlib.h> // 调用exit函数会执行以下操作: // 1、调用用户注册的清理函数 // 2、刷新缓冲区并关闭所有标准IO流 // 3、删除临时文件 // 4、调用_exit系统调用 exit(0); } else if (strcmp("_Exit", argv[1]) == 0) { // 作用:直接终止当前进程(含进程的所有线程) // 标准库函数(C99) // #include <stdlib.h> // 效果等同于_exit,但移植性更好。 _Exit(0); } else if (strcmp("_exit", argv[1]) == 0) { // 作用:直接终止当前进程(含进程的所有线程) // 是对exit_group系统调用的包装(可退出所有线程) // #include <unistd.h> _exit(0); } return EXIT_SUCCESS; // main函数return会调用exit函数}