声明: 1. 本文为我的个人复习总结, 并非那种从零基础开始普及知识 内容详细全面, 言辞官方的文章
2. 由于是个人总结, 所以用最精简的话语来写文章
3. 若有错误不当之处, 请指出
子进程:
由fork( )创建, 该函数被调用一次,但返回两次(子进程的返回值是0,而父进程的返回值是子进程id)
子进程得到的只是父进程的拷贝(拷贝其内存空间, 代码空间, 数据空间, 程序计数器pc值),而不是父进程本身
僵尸进程:
子进程结束了, 但父进程暂未对其资源进行回收; task_struct结构还保存在进程列表中
孤儿进程:
在回收僵尸进程之前, 如果父进程结束了,则僵尸进程变为孤儿进程,进而被init进程接管、回收
注意: ps出来以Z开头的便是僵尸进程, kill -9 并不能直接死僵尸进程
为什么需要僵尸进程(保留task_struct
)?
因为task_struct
里面保存了进程的pid、退出码、以及一些统计信息, 父进程可能会关心这些信息
如何处理僵尸进程?
三个方案:
-
父进程调用wait( )/waitpid( )
缺点: wait调用是阻塞的, 如果调用wait时子进程还没有退出, 将阻塞住父进程 影响性能
-
kill父进程
使僵尸进程变为孤儿进程, 从而被init进程接管、回收
缺点: 父进程可能还有作用, 不该随随便便杀死
-
通过进程通信的信号机制 异步回调通知进行回收 (最佳)
编写程序时, 子进程退出前向父进程发送
SIGCHLD
信号; 父进程回调函数收到SIGCHLD
信号后 便去调用wait( )/waitpid( ) 回收 子僵尸进程
什么时候会发生 僵尸进程一直不被回收 的情况?
在采用第三种方案时, 如果父进程是一个循环 永久不会结束, 那么子进程就会一直保持僵尸状态