_exit、_Exit、exit函数可以用于正常终止一个进程,其中_exit和_Exit立即进入内核,exit则先执行一些清理工作(包括调用执行个终止处理程序,关闭所有标准IO流等),然后进入内核。
3个函数的原型如下:
#include <stdlib.h> //ISO C说明
void exit(int status);
void _Exit(int status);
#include <unistd.h> //POSIX.1说明
void _exit(int status);
exit函数总是执行一个标准IO库的清理关闭操作:为所有打开流调用fclose函数,将所有缓冲的输出数据写到文件上。
3个函数都带有一个整型参数作为终止状态。
main函数终止时如果没有显示使用return语句或调用exit函数,则进程终止状态是未定义的。
当子进程比父进程先终止时,内核为每个终止子进程保存一些信息,当父进程调用wait或waitpid时,可以获取这些信息。这些信息至少包括了进程ID、进程终止状态、及该进程使用CPU时间总量。内核可以释放终止进程所使用的所有存储区,关闭其打开文件。
一个已终止、但父进程尚未对其进行善后处理(获取终止子进程的有关信息,释放所占用资源)的进程称为僵尸进程(zombie)。ps命令显示僵尸进程状态为Z。
当一个子进程的父进程在它终止之前终止了,则该子进程的父进程会变为init进程(ID = 1)。称这些进程有init进程领养。init进程中只要子进程终止,init会调用一个wait函数获取其终止状态。防止系统中产生很多僵尸进程。
一个避免僵尸进程的方法是,父进程创建一个子进程,该子进程在创建一个子进程来执行正常的工作,第一子进程在创建完成立即调用exit返回,父进程对第一个子进程使用wait等待。这样当第一个子进程调exit,父进程不会阻塞太久就能继续工作,而第二个子进程(即第一个子进程的子进程)在父进程执行完wait后,它会被init进程收养,这样就避免了当进程终止后没被及时处理而变成僵尸进程。
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
int main(void)
{
pid_t pid;
if((pid = fork()) == 0) //first child
{
if(fork() > 0) //second child
exit(0);
sleep(1); //wait first child first done
printf("second child, parent pid = %d\n", getppid()); //show second child's parent's id
//more work
exit(0);
}
waitpid(pid, NULL, 0);
exit(0);
}
输出:
按理来说第二个子进程在waitpid()语句执行后应该由init进程领养,所以输出的父进程id应该是1。可是我运行的时候不知道为什么输出的是另一个进程的id。