进程退出 和 僵尸进程、孤儿进程
PCB(task_struct)中的退出状态存储
exit_code
:记录进程的退出码。-
exit_signal
:记录导致进程终止的信号码(如SIGINT=2
)。 -
core_dump
:标记是否生成核心转储文件。 - state:记录进程状态
也就是说pcb中退出码和信号码是分开存的
进程退出函数
1._exit(n)
_exit 是一个系统调用,_exit会设置进程的退出码为n,设置进程状态为Z僵尸状态,将进程从运行队列里删除,释放pcb的资源的空间如文件、页表、物理内存块,不会释放pcb本身空间
2.exit(n)
exit是c语言库函数,FILE是文件的用户级数据结构,exit首先将FILE维护的用户级缓冲区刷新,之后会调用atexit所设定的清理函数,最后调用_exit
3.return n
如果是main里面的return,其作用和exit(n)或_exit(n)一样,具体看怎么实现,如果不是main里面的return那就是返回给上层结果
进程的退出
1.正常退出
_exit,exit,return进程退出的方式是正常退出,pcb里只有退出码,信号码是0
2.异常退出
如果信号处理是使进程退出,那么信号处理函数会设置pcb里的信号码,设置pcb里的进程状态为Z,将进程从运行队列里删除,释放pcb管理的资源的空间,退出码是0
3.父进程wait(&staus)
从父进程的子进程链表中找僵尸状态的子进程,wait会根据僵尸进程的退出信息来构建输出型参数status,低16位被使用,其中低7位填充信号码,第8位是核心转储,高8位是退出码
wait会释放僵尸进程的pcb本身的空间,至此该进程才算完全退出
退出码和信号码的范围
退出码是8位,0~255,0表示成功,1~255表示错误
信号码是7位,1~127,信号码没有0信号
$?变量
1.是shell维护的全局变量,保存上一个退出进程的退出信息
2.设置规则是如果进程正常退出那$?直接就是退出码(0~255),如果是异常退出那就是信号码+128(129~255)
父进程先于子进程退出
子进程还没跑完父进程已经退出了,这时会将父进程的所有子进程托管给init进程,这时的子进程称为孤儿进程,等子进程运行完,由init进程定时wait来回收释放子进程
父进程不wait
子进程已经退出了,父进程却迟迟不wait,直到父进程自个也退出了,这时也会把父进程的所有子进程托管给init进程,由init进程定时wait来回收释放子进程
孤儿进程
父进程已终止,被内核强制托管给init进程(PID=1)的存活进程
父进程wait时的阻塞与唤醒
调用wait,会扫描子进程链表,如果有僵尸子进程,那就构建status,释放pcb本身空间,如果没有僵尸子进程,那就把父进程挂到子进程等待队列上。
子进程退出时,无论是_exit正常退出还是信号处理函数异常退出,都会给等待队列上的进程设置SIGCHLD信号,并唤醒进程,等到父进程重新被调度,从上次wait的阻塞点开始运行,wait会先处理事务也就是回收并释放僵尸子进程,并且会丢弃对应SIGCHLD信号