今天我给大家讲讲linux命令退出的用法和区别。荣信教育提醒大家,北京空这两天不太好,同学们要注意呼吸道疾病的感染。好吧,我们来看看。
注意:exit()是exit。传入的参数是程序退出时的状态代码。0表示正常退出,其他表示异常退出。一般用-1或1。规范C中有两个宏,EXIT_SUCCESS和EXIT_FAILURE,使用exit(EXIT_SUCCESS)。可读性更好。
就系统调用而言,_exit和exit是孪生兄弟。他们到底相似到什么程度,我们可以从Linux的源代码中找到答案:
#define __NR__exit __NR_exit /*取自文件include/asm-i386/unistd.h,第334行*/
“__NR_”是Linux源代码中每个系统调用添加的前缀。请注意,第一个出口前有2个下划线,第二个出口前只有1个下划线。这时候任何懂C语言,头脑清醒的人都会说_exit和exit没有区别,但先说两者的区别,主要体现在函数库中对它们的定义上。Linux库中_exit的原型是:
#i包括void _exit(int状态);
和exit相比,exit()函数是在stdlib.h中定义的,而_exit()是在unistd.h中定义的,从名字上看,stdlib.h好像比unistd.h高一点,那么,两者有什么区别呢?_exit()函数的作用最简单:直接停止进程,抹掉它使用的内存空并破坏它在内核中的各种数据结构;exit()函数在这些的基础上做一些打包,在执行退出之前添加几个进程。基于这个原因,有人认为退出不能再被视为简单的系统调用。exit()函数和_exit()函数最大的区别在于,exit()函数在调用exit系统之前要检查文件打开状态,并将文件缓冲区中的内容写回文件,即“整理I/O缓冲区”。
退出()在完成调用它的过程之前,应该执行以下过程:
1.调用atexit()注册的函数(exit函数);ATEXIT注册的所有函数在注册时都是按相反的顺序调用的,这使得我们可以指定在程序停止时执行自己的排序动作,比如将程序状态信息保存在文件中,解锁共享数据库等等。
2 . clean up();关闭所有打开的流,这将导致写入所有缓冲的输出,并删除TMPFILE函数创建的所有临时文件。
3.最后调用_exit()函数停止进程。
_exit做三件事(man): 1,任何打开的文件deors相信该进程是关闭的2,该进程的任何子进程被进程1继承,init 3,该进程的父进程被发送一个sigchld信号。
Exit calls _exit在完成完成作业后停止进程。
此外,另一种解释:
简而言之,exit函数停止调用过程。退出程序前,关闭所有文件,缓冲输出内容会重写定义,所有重写的“退出函数”(由atexit定义)都会被调用。
_exit:此函数由Posix定义,不会运行退出处理程序和信号处理程序。在UNIX系统中,输入输出流不会被刷新。
简言之,_exit停止调用进程,但不关闭文件、擦除输出缓存或调用exit函数。
一起:
不管进程如何停止,内核都会关闭进程打开的所有文件deors,释放进程使用的内存!
更详细的介绍:
调用exit()exit()函数导致正常程序终止。
exit()函数执行以下功能:
1.标准C atexit()函数注册的所有函数都以注册的相反顺序调用。如果这些函数调用exit(),结果是不可移植的。2.所有打开的输出流被刷新(数据被写出),并且这些流被关闭。
3.由tmpfile()创建的所有文件都将被删除。
4.调用了_exit()函数。调用_exit()函数执行操作系统特定的程序终止函数。这些包括:1。所有打开的文件和目录流都被关闭。
2.如果父进程正在执行wait()或waitpid(),父进程将被唤醒,状态变为可用。
3.如果父进程没有执行wait()或waitpid(),则保存状态以便在后续的wait()或waitpid()上返回给父进程。4.终止进程的子进程被分配一个新的父进程标识。注:父母的终止并不直接终止其子女。如果实现支持SIGCHLD信号,就向父级发送一个SIGCHLD。6.发送几个作业控制信号。
为了在分叉子流程分支中使用_exit函数而不是exit函数?“exit()”和“_ exit()”之间有很多区别,尤其是“vfork()”。
“exit()”和“_exit()”的根本区别在于,前一个调用在调用库中实现与用户模式构造相关的清理,并调用用户定义的清理程序(自定义的清理程序由atexit函数定义,可以重复定义,也可以按相反的顺序执行)。相应地,_ exit函数只是一个进程。在' fork()'创建的子进程分支中,正常情况下使用' exit()'是不正确的,因为stdio: Standard Input Output)的缓冲区被清空空两次,临时文件被意外删除(临时文件是在系统的临时目录下由tmpfile函数创建的,文件名是系统随机取的)在C++程序中,情况会更糟,因为静态对象的析构函数可以执行错误。(也有一些特殊情况,比如照顾者,其父进程需要调用' _ exit()'而不是子进程;适用于大多数情况的基本规则是,在进入“main”函数后,只调用一次“exit()”。在‘vfork()’创建的子流程分支中,‘exit()’的应用会变得越来越有风险,因为会影响父流程的状态。
# include# include int glob = 6;/*初始化数据中的外部变量*/int main(void){ int var;/*堆栈上的自动变量*/PID _ t PID;var = 88printf("先于vfork n ";/*我们不刷新stdio */if((PID = vfork())& lt;0) printf("vfork错误 n ";else if(PID = = 0){/* child */glob++;/*修改父变量*/var++;退出(0);/* child terminals *///最好在子进程中使用_exit(0)。} /* parent */ printf("pid = %d,glob = %d,var = %dn ",getpid(),glob,var);退出(0);}运行在Linux系统上,父进程printf的输出:pid = 29650,glob = 7,var = 89
子进程是自己关闭的。虽然它们共享规范输入、规范输出、规范错误等“打开的文件”,但是当子进程退出时,它只是递减引用计数,使得父进程无法关闭,所以父进程仍然有输出。
但是,在其他UNIX系统上,父进程可能没有输出。最初的原因是子进程调用e x i t,覆盖并关闭所有规范的I/O流,包括规范的输出。虽然这是由子进程执行的,但它是在父进程的地址空中执行的,因此所有受影响的规范I/O FILE目标都在父进程中。当父进程调用p r i n t f时,规范输出已经关闭,所以p r i n t f返回-1。
在Linux的标准函数库中,有一组函数叫做“高级I/O”,众所周知的有printf(),fopen(),fread()和fwrite()。它们也被称为“缓冲I/O”,它们的特点是内存中有一个缓冲区,对应于每个打开的文件,这样,下次读取文件时,可以直接从内存中的缓冲区读取。每次写文件,都是只写到内存中的缓冲区。在满足一定条件(达到一定数量,或者遇到特定字符,比如换行符、文件完成符EOF)后,可以将缓冲区的内容一次性写入文件,大大提高了文件读写的速度,但也给我们的编程带来了一点麻烦。如果有一些数据,我们认为已经写入文件,但实际上,因为不满足指定条件,所以只存储在缓冲区中。此时,我们使用_exit()函数直接关闭进程,缓冲区中的数据将会丢失。相反,如果我们想确保数据的完整性,就必须使用exit()函数。
Exit的函数在stdlib.h头文件中声明。
_exit的函数在unistd.h头文件中声明。
以下示例比较了这两个函数之间的差异。Printf函数是一种缓冲I/O的方法,遇到“n”换行符时主动从缓冲区读取记录。使用此属性比较示例。
Exit.c源代码
# include # include int main(void){ printf("使用退出... n ");printf("这是缓冲区中的内容");退出(0);}
输出信息:
使用退出...
这是缓冲区中的内容
# include # include int main(void){ printf("使用退出... n ");//如果此处没有添加“n”,此消息可能不会出现在终端上。printf("这是缓冲区中的内容");_ exit(0);}
仅输出:
使用退出...
澄清:一个进程调用exit后,该进程不会立即完全消失,而是留下一个叫僵尸的数据结构。僵尸进程是一个非常特殊的进程,已经放弃了所有的内存空,没有可执行代码,无法调度。它只在流程列表中保存一个位置,记录流程的退出状态和其他信息,供其他流程收集。况且僵尸进程不再占用任何内存空。
# include
int main() { printf("%c ",' c ');_ exit(0);}文章来自荣信教育官网:www.vfast.com.cn欢迎访问,需要注明出处
1.《exit函数 linux命令之exit分析》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。
2.《exit函数 linux命令之exit分析》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/yule/795566.html