在 UNIX 里,除了程序 0(即 PID=0 的交换程序,Swapper Process)以外的所有程序都是由其他程序使用系统呼叫 fork 建立的,这里呼叫 fork 建立新程序的程序即为父程序,而相对应的为其建立出的程序则为子程序,因而除了程序 0 以外的程序都只有一个父程序,但一个程序可以有多个子程序。
操作系统核心以程序识别符号(Process Identifier,即 PID)来识别程序。程序 0 是系统引导时建立的一个特殊程序,在其呼叫 fork 建立出一个子程序(即 PID=1 的程序 1,又称 init)后,程序 0 就转为交换程序(有时也被称为空闲程序),而程序 1(init 程序)就是系统里其他所有程序的祖先。
 
一、僵尸程序
1、什么是僵尸程序?
当一个子程序结束执行(一般是呼叫 exit、执行时发生致命错误或收到终止讯号所导致)时,子程序的退出状态(返回值)会回报给操作系统,系统则以 SIGCHLD 讯号将子程序被结束的事件告知父程序,此时子程序的程序控制块(PCB)仍驻留在内存中。一般来说,收到 SIGCHLD 后,父程序会使用 wait 系统呼叫以取得子程序的退出状态,然后核心就可以从内存中释放已结束的子程序的 PCB;而如若父程序没有这么做的话,子程序的 PCB 就会一直驻留在内存中,也即成为僵尸程序。
 
2、僵尸程序的危害
由于子程序的结束和父程序的执行是一个非同步过程, 即父程序永远无法预测子程序 到底什么时候结束. 那么不会因为父程序太忙来不及 wait 子程序, 或者说不知道子程序什么时候结束, 而丢失子程序结束时的状态资讯呢? 不会. 因为 UNIX 提供了一种机制可以保证 只要父程序想知道子程序结束时的状态资讯, 就可以得到. 这种机制就是: 在每个程序退出的时候, 核心释放该程序所有的资源, 包括开启的档案, 占用的内存等. 但是仍然为其保留一定的资讯 (包括程序号 the process ID, 退出状态 the termination status of the process, 执行时间 the amount of CPU time taken by the process 等), 直到父程序通过 wait / waitpid 来取时才释放. 但这样就导致了问题, 如果你程序不呼叫 wait / waitpid 的话, 那么保留的那段资讯就不会释放, 其程序号就会一定被占用, 但是系统所能使用的程序号是有限的, 如果大量的产生僵死程序, 将因为没有可用的程序号而导致系统不能产生新的程序. 此即为僵尸程序的危害应当避免。
 
3、僵尸程序的清理
为避免产生僵尸程序,实际应用中一般采取的方式是:
1)将父程序中对 SIGCHLD 讯号的处理函式设为 SIG_IGN(忽略讯号);
2)fork 两次并杀死一级子程序,令二级子程序成为孤儿程序而被 init 所 “收养”、清理。
 
二、 孤儿程序
1、什么是孤儿程序?
孤儿程序则是指父程序结束后仍在执行的子程序。在类 UNIX 系统中,孤儿程序一般会被 init 程序所 “收养”,成为 init 的子程序。
 
2、孤儿程序的危害
孤儿程序是没有父程序的程序,孤儿程序这个重任就落到了 init 程序身上,init 程序就好像是一个民政局,专门负责处理孤儿程序的善后工作。每当出现一个孤儿程序的时候,核心就把孤 儿程序的父程序设定为 init,而 init 程序会回圈地 wait() 它的已经退出的子程序。这样,当一个孤儿程序凄凉地结束了其生命周期的时候,init 程序就会代表党和政府出面处理它的一切善后工作。因此孤儿程序并不会有什么危害。
 
三、Linux 中的程序基本状态:
1、执行 (R) 状态:CPU 正在执行,即程序正在占用 CPU。
2、就绪 (W) 状态:程序已经具备的执行的一切条件,正在等待分配 CPU 的处理时间片。
3、停止 (S) 状态:程序不能使用 CPU。
四、三个函式:
fork(); 功能: 建立一个新的程序。(fork()<0[出错]、fork()==0[子程序]、fork()>0[父程序]
wait(); 功能:真正结束程序(收尸)。
exec(); 功能:执行外部程式。
孤儿程序与僵尸程序的区别:
僵尸程序会造成资源浪费,孤儿程序则不会!