进程退出表示进程即将结束运行。
1.正常退出
- 在main函数中执行return。
- 调用exit函数。
- 调用_exit函数。
2.异常退出
- 调用abort函数
- 进程收到某个信号,该信号使程序终止。
进程退出后都会将所有已打开的文件描述符关闭,释放它所占用的内存和其他资源
各种退出方式之间的比较:
- exit和return:exit是一个函数,有参数;return是函数执行完后的返回。exit把控制权交给系统,return将控制权交给的调用函数。
- exit和abort:exit是正常终止进程,abort是异常终止。
- exit(int exit_code):exit中的参数为0代表进程正常终止,若为其他表示程序执行过程有错误发生。
- exit()和_exit:exit在stdlib.h中声明,而_exit声明在unistd.h中。两函数均表示正常终止进程。但_exit()会执行后立即返回给内核,而exit()要先执行一些清除操作后才将控制权交给 内核。
父子进程终止的先后顺序回产生不同的结果,子进程退出前父进程先退出,则会产生孤儿进程,由init进程接管。当子进程先于父进程终止,而父进程又没有调用wait函数等待子进程结束,子进程就回进入僵死状态,子进程进入僵死状态之后内核只保存该进程的一些必要信息以备父进程所需。若父进程调用了wait或waitpid函数,则父进程会等待子进程结束。
下面这个例子解释了关于退出时的内存释放与否与不同的退出方式之间的联系:
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
int globvar = 5;
int main(void)
{
pid_t pid;
int var = 1, i;
printf("fork is diffirent with vfork\n");
pid = vfork();
switch(pid)
{
case 0:
i = 3;
while(i-- > 0)
{
printf("child process is run\n");
globvar++;
var++;
printf("child var = %d\n", var);
sleep(1);
}
printf("child globvar = %d, var = %d\n", globvar, var);
break;
case -1:
perror("parent process failed\n");
exit(0);
default:
i = 5;
while(i-- > 0)
{
printf("parent process is running\n");
globvar++;
var++;
printf(" parent var = %d\n", var);
sleep(1);
}
printf("parent's globvar = %d, var = %d\n", globvar, var);
exit(0);
}
}
这段代码本来是要测试vfork创建的子进程与父进程公用同一块内存空间,也就是子进程对变量的改变对父进程是可见的。但最终的结果却出乎意料:
当子进程退出之后,父进程本来应当接着子进程的var进行递加的,但是最终的结果却是子进程退出,父进程的var成为了随机值,后来我在程序的最后添加了exit(0)之后程序的执行结果就变成了这样:
变量的结果正常了,这是因为在之前case 0时子进程的退出在break之后并未做任何退出函数的调用于是默认是以return结束这个函数的,那么return的退出是函数的退出,函数的退出是会清除在函数内部的局部变量的。所以var值被释放,变成了随机值。当在最后添加exit(0)之后,exit并不会释放栈内存,所以结果正常了。