glibc exit 之前写过一篇介绍 linux 进程环境的文章(《 [apue] 进程环境那些事儿》),其中提到了 glibc exit 会主动调用 atexit 注册的处理器,且有以下特性: LIFO...,先进后出的顺序 注册几次调用几次 atexit 处理器中再次调用 exit 能完成剩余处理器的调用 atexit 处理器中再次注册的 atexit 处理器能被调用 下面带着这些问题,来看 glibc...处理线程局部存储的释放,这里不涉及主题,略过 主循环加锁遍历处理器 deque 处理 libc 的 atexit 列表,略过 调用 _exit 退出进程 重点就落在中间的两个 while 循环上,外层用于遍历块...字段都指向同一个地址 处理器中调用 exit 能完成剩余处理器的调用,原因分为两个方面: 处理器回调前已经解锁,因此再次调用 exit 时可以正常进入这里 处理器回调前已经把标志设为了 ef_free...结语 从这里也可以看到一个标准的 atexit 需要考虑的问题: 程序运行期间单向增长 程序退出时反向减少 有可能在执行回调时注册新的处理器从而导致再次增长,所以并不是单向减少 代码优化 glibc 主要花费了大量的精力处理第三个场景
,父进程获取到的是最近一个子进程退出的退出码,前面我们提到,echo是内建命令,打印的都是bash内部的变量数据 父进程bash为什么要得到子进程的退出码呢?...要知道子进程退出的情况(成功,失败,失败的原因是什么?) 进程结束时,可以通过 return 语句(在函数中)或 exit() 函数(直接从程序中)指定一个退出码。...理解这些区别有助于正确地管理程序的终止过程,特别是在涉及资源清理和子进程管理时。 exit() exit() 函数是由 C 标准库提供的,用于结束程序。..._exit() _exit() 函数是由 POSIX 标准指定,直接调用系统级别的退出操作,用于立即结束程序,不执行标准 I/O 的清理操作和不调用 atexit() 或者 C++ 的全局对象的析构函数...立即终止:提供一种确保程序能迅速终止的方式,通常用于子进程退出或者在错误处理中需要立即终止程序时使用。
import sys print("程序开始运行") sys.exit(0) print("这行代码永远不会被执行") 在上面的代码中,sys.exit(0) 表示正常退出程序,而不会抛出错误。...import atexit def cleanup(): print("程序退出前执行清理操作...")...atexit.register(cleanup) print("程序正在运行...") sys.exit(0) 在上面的代码中,atexit.register() 注册了一个清理函数,在程序正常退出之前会被执行...通过 atexit 来注册退出前的清理操作,结合 join() 来确保所有线程都已安全结束,避免了线程未结束就强行退出的问题。..._exit(): 立即终止进程,不会触发任何清理操作,如 finally 块或 atexit 钩子。这通常用于在子进程中终止程序。
: 一个进程可以登记多达32个函数,这些函数将由exit自动调用,通常这32个函数被称为终止处理程序,并调用atexit函数来登记这些函数,atexit的参数是一个函数地址,当调用此函数时无须传递任何参数...,该函数也不能返回值,atexit函数称为终止处理程序注册程序,注册完成以后,当函数终止是exit()函数会主动的调用前面注册的各个函数,但是exit函数调用这些函数的顺序于这些函数登记的顺序是相反的,...,但程序退出的方式有很多种,比如main()函数运行结束、在程序的某个地方用exit()结束程序、用户通过Ctrl+C或Ctrl+break操作来终止程序等等,因此需要有一种与程序退出方式无关的方法来进行程序退出时的必要处理...关于exit: exit函数运行时首先会执行由atexit()函数登记的函数,然后会做一些自身的清理工作,同时刷新所有输出流、关闭所有打开的流并且关闭通过标准I/O函数tmpfile()创建的临时文件。...exit()函数用于在程序运行的过程中随时结束程序,exit的参数state是返回给操作系统,返回0表示程序正常结束,非0表示程序非正常结束 exit()函数用于在程序运行的过程中随时结束程序,其原型为
参考链接: C++ atexit() 很多时候我们需要在程序退出的时候做一些诸如释放资源的操作,但程序退出的方式有很多种,比如main()函数运行结束、在程序的某个地方用exit()结束程序、用户通过Ctrl...+C或Ctrl+break操作来终止程序等等,因此需要有一种与程序退出方式无关的方法来进行程序退出时的必要处理。...在一个程序中至少可以用atexit()注册32个处理函数(你至少可以32次,这依赖于你的编译器),这些处理函数的调用顺序与其注册的顺序相反,也即最先注册的最后调用,最后注册的最先调用。...这里需要纠正一下网上很多人的错误说法,他们说atexit()最多可以被调用32次,而实际上是atexit最少可以被调用32次。 函数说明:atexit()用来设置一个程序正常结束前调用的函数....当程序通过调用exit()或从main 中返回时, 参数function 所指定的函数会先被调用, 然后才真正由exit()结束程序.返回值:如果执行成功则返回0, 否则返回-1, 失败原因存于errno
从进程调度器中移除该进程,使其不再执行。 进程的终止一般由三种情况触发: 代码运行完成,正常终止(例如 return 0)。...main函数的返回值通常表明程序的执行情况,通过不同的返回值可以表明程序运行正常或者通过数字表明出错原因,这个返回值就是进程退出码。...父进程要知道子进程的运行情况,所以退出码会存在于子进程的PCB中,即使代码和页表数据清除也可以得到子进程信息。...进程终止的常见方法 在 Linux 系统中,进程终止的常见方法包括以下几种: 正常终止 正常终止指的是进程按照预期逻辑完成任务并退出,可以使用以下方式: return 语句 当 main() 函数执行...获取最近终止进程的退出码。例如: ./my_program echo $?
fork常规用法 一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如,父进程等待客户端请求,生成子进程来处理请求。 一个进程要执行一个不同的程序。...如果子进程运行完成,结果对还是不对,或者是否正常退出。 父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息。...; 返回值: 当正常返回的时候waitpid返回收集到的子进程的进程ID; 如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0; 如果调用中出错,则返回-...获取子进程status wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。 如果传递NULL,表示不关心子进程的退出状态信息。...进程程序替换 替换原理 用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。
#include pid_t fork(void); 返回值:自进程中返回0,父进程返回子进程id,出错返回-1 进程调用fork,当控制转移到内核中的fork代码后,内核做: 分配新的内存块和内核数据结构给子进程...例如,父进程等待客户端请求,生成子进程来处理请求。 一个进程要执行一个不同的程序。例如子进程从fork返回后,调用exec函数。...之前,还做了其他工作: 执行用户通过 atexit或on_exit定义的清理函数。..., int options); 返回值: 当正常返回的时候waitpid返回收集到的子进程的进程ID; 如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集...获取子进程的status wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。 如果传递NULL,表示不关心子进程的退出状态信息。
如果你英文不太好,没关系,这里先提供谷歌翻译给你~ 名称 退出-导致正常进程终止 概要 #include void exit(int...(这些功能之一可能 使用atexit(3)或on_exit(3)来注册要在退出处理期间执行的其他功能的说明;新注册已添加到 如果这些函数之一未返回(例如,它调用_exit(2...)或使用 信号),则不调用其余功能,而放弃进一步的退出处理(特别是stdio(3)流的刷新)。...由tmpfile(3)创建的文件将被删除。...源文件-->预处理-->编译-->汇编-->链接-->可执行文件 预处理 以#开头的命令称为预处理命令,像#include, #if, #ifndef, #indef等命令,预处理是将宏定义展开,根据条件编译选择使用到的代码
当⼀个进程调⽤fork之后,就有两个⼆进制代码相同的进程。⽽且它们都运⾏到相同的地⽅。但每个进 程都将可以开始它们⾃⼰的旅程,看如下程序。...fork常规⽤法以及调用失败的原因 ⼀个⽗进程希望复制⾃⼰,使⽗⼦进程同时执⾏不同的代码段。例如,⽗进程等待客⼾端请求,⽣成⼦进程来处理请求。 ⼀个进程要执⾏⼀个不同的程序。...在命令结束以后,我们可以知道命令是成功完成的还是以错误结束的。其基本思想是,程序返回退出代码 0 时表⽰执⾏成功,没有问题。 代码 1 或 0 以外的任何代码都被视为不成功。...: 当正常返回的时候waitpid返回收集到的⼦进程的进程ID; 如果设置了选项WNOHANG,⽽调⽤中waitpid发现没有已退出的⼦进程可收集,则返回0; 如果调⽤中出错,则返回-1,这时errno...获取⼦进程status wait和waitpid,都有⼀个status参数,该参数是⼀个输出型参数,由操作系统填充。 如果传递NULL,表⽰不关⼼⼦进程的退出状态信息。
具体见下图: 1.3 fork常规用法 一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如,父进程等待客户端请求,生成子进程来处理请求 一个进程要执行一个不同的程序。...: 执行用户通过 atexit或on_exit定义的清理函数。...); 返回值: 当正常返回的时候waitpid返回收集到的子进程的进程ID; 如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0; 如果调用中出错,则返回-...如果不存在该子进程,则立即出错返回 3.2.3 获取子进程status wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充 如果传递NULL,表示不关心子进程的退出状态信息...否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程 status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特位): 测试代码: #include
main函数执行用户的主功能代码。 startGlue函数执行exit退出程序,收回资源,结束进程。...上面说了进程结束回调注册函数会在进程结束时被调用,而进程结束的函数是exit函数,因此可以很容易就想到这些回调函数的执行肯定是在exit函数内部调用的,事实也确实如此,通过汇编代码查看exit的实现如下...异常退出和abort函数 如果进程正常退出,最终都会执行exit函数。exit函数内部会调用atexit函数注册的所有回调,以便有时间进行一些资源的回收工作。...通过上面对main函数执行前所做的事情,以及进程结束前我们能做的事情的介绍,您是否又对程序的启动时和结束时所发生的一切有了更加深入的理解。...上面就是我要介绍的C++全局对象的构造函数和析构函数的调用以及实现的所有过程。我们从上面的章节中还可以了解到程序在启动和退出这个阶段所做的事情,以及我们所能做的事情。
规定了程序和计算机硬件直接所允许发生的一切交互。 进程是 Unix 系统的基石,所有的代码都是在进程中运行。 unix 中的进程创建是通过内核系统调用 fork() 实现的。...as e: print('error', e) # 这里将打印 exit 中的参数 2 sys.exit() 会引发一个异常,如果异常没有被捕获,那么 python 解释器将会退出。...test) sys.exit() # 也可以是 raise 当 exit 被调用时,在进程结束之前,python 会调用 atexit 所定义的语句。...所以这段代码中,if 语句由子进程执行,而 else 语句由父进程执行。 考虑一个问题: 由于 fork 的时候创建了一个和父进程一模一样的子进程,它包含了父进程在内存中的一切内容。...孤儿进程 当通过终端启动单个进程时,通常只有这个进程向 STDOUT 写入,从键盘获取输入或者侦听 Ctrl+C 已待退出。
: 代码运行完毕,结果正确 代码运行完毕,结果不正确 代码异常终止:异常退出本质是收到了对应的信号 进程退出的常用方法 return exit _exit 那么谁会关心一个进程的运行情况呢?...exit和_exit exit 和 _exit 都可以退出进程,但是exit在退出进程前会做其它工作: 执行用户通过 atexit或on_exit定义的清理函数。...参数: 输出型参数,获取子进程退出状态,不关心则可以设置成为NULL. wait等待的是任意一个子进程 实例: #include #include 的原理: 其实子进程在退出的时候,会把退出码,终止信号写入到PCB的 exit_code 和 exit_signal 变量中,等待进程时,也就是从子进程的PCB中读取这两个变量的值,并写入到输出型变量...即在子进程退出前,父进程什么也不做,一直在等着子进程退出,此时父进程处于阻塞状态。
3.将子进程的PCB加入到调度队列中,从此子进程开始自己的旅程; 1.2写时拷贝 1.3fork函数的作用 1.创建子进程让其帮忙执行任务,例如:父进程等待客户端请求,生成子进程来处理请求。...之前还执行了其他的操作进行资源清理 1.执行用户通过 atexit或on_exit定义的清理函数。...(_exit压根看不到缓冲区,所以这个工作只能有exit去完成) 2.6 异常终止 一旦程序发生异常那么就程序就会直接中断,但是异常是事先知道异常的条件的,比如不能/0,一旦异常那么就不会正常接收退出码了...,然后继续执行后序的代码,这个时候就需要等待子进程完成任务后,获取子进程的退出码看看他完成的怎么样了; 2.避免僵尸进程:子进程先父进程结束会出现僵尸状态,造成进程卡死,无法回收,所以我们只需要阻塞父进程让他等待子进程完成...,那么父进程将不会一直阻塞,而是会返回0后继续执行后面的代码,如果子进程退出了,那么返回子进程的PID; 返回值: 正常执行(没有设置WNOHANG):此时和wait一样; 等待成功就会返回子进程pid
注册的清理程序 在清理程序中调用 exit "无效",如果调用 _exit 或 _Exit,会导致程序直接退出,后续清理程序不再被调用 进程异常终止时清理程序不会被调用 下面这个例子验证了调用次数与 FILO...3 进入 bye 处理程序后进程就终止了,后续的处理程序不再调用。检查进程结束状态码为 3,正好是 _exit 的 status 参数。...^C 直到输入 Ctrl+C 才能退出,看起来 atexit 并不能检测这种情况,需要程序员自己避免调用环的形成,好在这种场景并不多见。...其中: 代码段也称正文段,存储可执行程序的机器指令部分,一般是只读、共享的 初始化数据段也称为数据段,包含了程序中明确赋初值的全局或静态变量,以上两段从程序文件中读入 非初始化数据段也称为 bss (block...由于不需要保存初始化值,程序文件中甚至没有这个段,它是由 exec 初始化为 0 的 堆,动态存储分配区域,由低地址向高地址增长 栈,自动变量及函数调用所需的信息存放在此段。
零、前言 前篇我们讲解学习了关于进程的概念知识,本章主要讲解关于进程的控制,深入学习进程 一、进程创建 1、fork函数 概念: 在linux中fork函数从已存在进程中创建一个新进程(子进程)...仅仅是退出进程 exit在退出进程前,先执行用户通过 atexit或on_exit定义的清理函数,关闭所有打开的流,所有的缓存数据均写入(刷新缓冲区),最后调用_exit 示图: 示例:...“内存池” 释放程序数据和代码占用的空间,并非清空数据和代码,而是将对应内存区域设置为无效,要再次使用时直接覆盖数据和代码就行了 取消曾经该进程在进程队列里的链接关系(避免”野指针“)...ID 如果设置了选项options为WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在...R 当到一定程度时,系统会唤醒进程,进程由等待队列转为运行队列,同时状态变为R 四、进程替换 1、替换原理 用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支)
如前所述,由继承得来的文件模式创建屏蔽字可能会被设置为拒绝权限。我们可以根据我们的具体需求设定特定的权限。 2、调用fork,然后使父进程exit。这样做,使得当我们以....这是为了保证守护进程的当前工作目录在一个挂载的文件系统中,该文件系统不能被卸载。 5、关闭不再需要的文件描述符。根据具体情况来定。...9、守护进程退出处理 当用户需要外部停止守护进程运行时,往往会使用 kill命令停止该守护进程。所以,守护进程中需要编码来实现kill发出的signal信号处理,达到进程的正常退出。..._exit(1) # 子进程, 由于父进程已经退出,所以子进程变为孤儿进程,由init收养 '''setsid使子进程成为新的会话首进程,和进程组的组长,与原来的进程组、控制终端和登录会话脱离..._exit(1) # 孙进程 # for i in range(3,64): # 关闭所有可能打开的不需要的文件,UNP中这样处理,但是发现在python中实现不需要。
,我们写应用程序时不用考虑引导代码的问题,编译连接时(准确说是连接时)由链接器将编译器中事先准备好的引导代码给连接进去和我们的应用程序一起构成最终的可执行程序。...最后当我们去执行一个程序时(譬如./a.out,譬如代码中用exec族函数(它就是提供了一个在进程中启动另一个程序执行的方法。...函数,atexit的参数是一个函数地址(或者说是一个函数指针),当调用此函数(指的是atexit的参数 )时无须传递任何参数,该函数也不能返回值,atexit函数称为终止处理程序注册程序,注册完成以后。...return、exit和_exit的区别:return和exit效果一样,都是会执行进程终止处理函数,但是用_exit终止进程时并不执行atexit注册的进程终止处理函数(类似于单片机的中断)。...所有的源代码可以到我的github里面获取:https://github.com/1121518wo/linux-/tree/master
另一个非常重要的因素,为什么使用 GOT 条目来获取控制权,而不是返回地址,是代码的形式(在一些“安全”指纹守护程序中发现): syslog (LOG_NOTICE, user); exit (EXIT_FAILURE...6.1.4 __atexit结构 几个月之前,Kalou 介绍了一种利用 Linux 下静态链接二进制的方式,它利用了叫做__atexit的通用处理器,只要你的程序调用了exit,它就会执行。...这允许程序建立很多处理器,它们会在退出时调用来释放资源。__atexit结构上的攻击的详细讨论,可以在 Pascal Bouchareines 的文章 [16] 中找到。...一些守护程序使用函数指针表来处理命令,例如 QPOP。同时,函数指针也通常用于模拟类似__atexit的处理器,例如 SSHD。...在运行这个补丁的系统中,几乎不可能执行引入该进程的任意 shellcode。但是多数情况下,在进程空间中已经有了实用的代码。我们可以执行这个代码来做通常在 shellcode 中所做的事情。
领取专属 10元无门槛券
手把手带您无忧上云