进程控制-进程终止(exit、_exit)

知道了进程怎么创建,接下来就来看看怎么终止一个进程终止函数exit()和_exit()。

函数头文件声明
exitstdlib.hvoid exit(int status)
_exitunistd.hvoid _exit(int status)

参数作用:可以利用这个参数传递进程退出状态。0表示正常退出,其他情况表示非正常结束。可以用wait接受来自子进程的退出码。在任意
⼀种情况下,该终⽌状态的⽗进程都能使⽤wait或waitpid函数取得其终⽌状态
1. exit()、_exit()
首先,exit()和_exit()都是用来终止进程的。当进程执行exit()或_exit()函数时,系统会立即停止所以操作,清除进程相关的各种数据结构,包括进程PCB,并且终止当前进程的运行。


这里写图片描述

可以看到,exit()函数的作用最为简单:直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构;exit() 函数则在这些基础上作了一些包装,在执行退出之前加了若干道工序,也是因为这个原因,有些人认为exit已经不能算是纯粹的系统调用。
那么exit()在结束调用它的进程之前都做了什么呢?

     exit调用系统调用exit()前先对文件的打开情况进行检查,关闭所有打开的流,这将导致写所有被缓冲的输出,删除用TMPFILE函数建立的所有临时文件。这里的缓冲就是图中的“I/O缓冲”。系统会为每个已经打开的文件,在内存定义一片缓冲区,这样我们每次写入数据都是先写入到缓冲区中,然后满足一定条件后再由缓冲区一次性写入到文件中。这样大大加快了文件读写的速度。
   
     简单的说就是,exit函数将终止调用进程。在退出程序之前,所有文件关闭,缓冲输出内容将刷新定义,并调用所有已刷新的“出口函数”(由atexit定义)。
而_exit同样终止调用进程,但不关闭文件,不清除输出缓存,也不调用出口函数。
所以当文件进行读写操作后,数据有可能在缓冲区,而这时候调用_exit则会将缓冲区的数据丢失,使得出现错误,数据不完整。因此当读写文件操作后,尽量使用exit()终止进程,避免意想不到的错误。
使用实例:

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 0;
int main()
{
 pid_t id = fork();
 if( id < 0 ){
 exit(1);
 }
 else if( id == 0 ){
 printf("clild is run, child pid is : %d\n",getpid());
 sleep(1);
 exit(100);
 }
 else{
 printf("father is run,father pid is : %d\n",getpid());
 }
 int ret;
 if( wait(&ret) < 0 ){
 printf("wait error, error code is : %d\n", errno);
 return 1;
 }
 printf("wait success, status code is : %d\n",ret);
 return 0;
}

结果:
这里写图片描述
2. 进程终止的特殊情况
1)子进程终止时,父进程并不正在执行 wait()调用。
2)当子进程尚未终止时,父进程却终止了。
在第一种情况中,要终止的进程就处于一种过渡状态 ,称为 僵死状态(zombie ),处于这种状态的进程不使用任何内核资源,但是要占用内核中的进程处理表那的一项。当其父进程执行wait()等待子进程时,它会进入睡眠状态,然后把这种处于过渡状态的进程从系统内删除,父进程仍将能得到该子进程的结束状态。
第二种情况中,对于⽗进程已经终⽌的所有子进程,他们的⽗进程都改变为init进程。我们称这些子进程由init领养。⼀个init的⼦进程(包括领养进程)终⽌时, init会调⽤⼀个wait函数取得其终⽌状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值