#include <unistd.h>
pid_t fork(void);
返回值:自进程中返回0,父进程返回子进程id,出错返回-1
进程调用fork,当控制转移到内核中的fork代码后,内核做:
写时拷贝
首先想清楚,终止是做什么:
进程退出场景:
上面的代码,进程11258为父进程bash,echo $?
,父进程获取到的是最近一个子进程退出的退出码,前面我们提到,echo是内建命令,打印的都是bash内部的变量数据
父进程bash为什么要得到子进程的退出码呢?要知道子进程退出的情况(成功,失败,失败的原因是什么?)
进程结束时,可以通过 return 语句(在函数中)或 exit() 函数(直接从程序中)指定一个退出码。这个退出码是一个整数,传递给父进程,用于表示子进程的终止状态。
常见惯例:
在操作系统中,进程的异常终止通常是由于一些错误或意外情况导致程序不能正常运行到结束。以下是一些典型的异常终止情况:
abort()
函数而触发。ValueError
或 IndexError
。一旦出现异常,退出码没有意义了!进程出异常,本质是因为进程收到了OS发给进程的信号!
段错误,OS提前终止进程
我们可以看进程退出的时候,退出信号是多少,就可以判断我的进程为什么异常了! ! !
衡量一个进程退出,我们只需要两个数字:退出码,退出信号!
正常退出:
_exit()
,系统调用异常退出:
在 Unix 和类 Unix 系统中,_exit()
和 exit()
都用于终止进程,但它们在功能和使用场景上有重要的区别。理解这些区别有助于正确地管理程序的终止过程,特别是在涉及资源清理和子进程管理时。
exit()
exit()
函数是由 C 标准库提供的,用于结束程序。它执行几个重要的清理操作,然后调用底层的 _exit()
或 exit_group()
系统调用来终止进程。
exit()
会自动刷新所有 stdio 的缓冲区,将缓冲区内的数据写入文件。这确保了所有挂起的输出(例如,使用 printf()
产生的输出)都被正确地写出。atexit()
注册的函数:如果程序中使用了 atexit()
注册了任何终止时执行的函数,exit()
会在实际终止进程前按注册的逆序调用这些函数。这可以用于执行一些如关闭文件描述符、释放分配的内存等清理工作。
使用场景主要是普通的应用程序,在需要确保输出数据完整性和执行特定的清理操作时使用。
_exit()
_exit()
函数是由 POSIX 标准指定,直接调用系统级别的退出操作,用于立即结束程序,不执行标准 I/O 的清理操作和不调用 atexit()
或者 C++ 的全局对象的析构函数。
atexit()
注册的函数:任何通过 atexit()
注册的函数都不会被执行。
使用场景主要是在创建子进程后,子进程完成任务立即退出时,或者在程序遇到无法恢复的错误需要立即终止时使用。
exit()
当你需要正常终止程序,并且需要清理资源(如关闭文件、保存状态等)。_exit()
在需要快速退出且不关心资源清理的场景下,比如在子进程中执行了某个任务后,或者在出现严重错误时安全退出。选择合适的函数可以避免数据丢失和资源泄漏,确保程序的稳定和安全。
return是一种更常见的退出进程方法。执行return n等同于执行exit(n),因为调用main的运行时函数会将main的返回值当做 exit的参数