薄雾浓云愁永昼————僵尸进程
一、进程
进程可以看做程序的一次执行过程。在linux下,每个进程都会被分配一个唯一的数字编号,我们称之为进程标识符或PID。PID是一个从1到32768的正整数,其中1一般是特殊进程init,其它进程从2开始依次编号。当用完32768后,从2重新开始。
在一台单处理器的计算机上,同一时间只有一个进程可以运行,其他程序处于就绪状态,该状态表示程序只要得到CPU就可以运行了。每个进程运行的时间是有限的,我们称作时间片,时间片是相当短暂的,这就给我们一种程序在同时运行的错觉。Linux内核用进程调度器来决定下一个时间片分配给那个进程,它的判断依据是根据进程的优先级。高优先级的进程运行得更频繁,但长期不间断运行的进程,优先级会变低,同时,低优先级的进程随着时间的推移,优先级会不断提升,直到其能够被执行。
二、父进程与子进程
子进程指的是由另一进程(对应称之为父进程)所创建的进程。一个进程可能下属多个子进程,但最多只能有1个父进程,而若某一进程没有父进程,则可知该进程很可能由内核直接生成。
三、僵尸进程
子进程终止时,其与父进程的关联还会保持,直到父进程也正常停止或调用wait函数,因此,进程表中子进程的表项不会立刻释放,虽然子进程已不再运行,但它仍然存在于系统中,因为他的退出码还需要保存起来此时他将成为一个死进程(defunct)或僵尸进程(zombie)。如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。
由上图我们可以看到,光标还在不停闪烁,表示在子进程运行完输出 B 后,父进程还在运行,于是子进程后面有了一个 defunct 标志,这就说明它现在是一个僵尸进程。
当然,当父进程正常结束后,僵尸进程就不存在了。
四、僵尸进程的应对方法
1、wait()函数
wait()函数一般用在父进程中等待回收子进程的资源,而防止僵尸进程的产生。
#include <sys/types.h>
#include <sys/wait.h>
pid_twait (int * status);
调用 wait 函数时,调用进程将会出现下面的情况:
· 如果其所有子进程都还在运行,则阻塞。
· 若某一子进程已经终止,则获取该子进程的终止状态,将其彻底销毁后立即返回。
· 如果没有任何子进程,则立即出错返回。
参数 status 是一个整形指针。如果status不是一个空指针(NULL),则子进程的终止状态将存储在该指针所指向的内存单元中。如果不关心终止状态,只是想将其销毁,可以将status参数设置为NULL。
如:pid = wait(NULL)
返回值:如果执行成功则返回被销毁的子进程PID,如果有错误发生(即无子进程)则返回-1
wait函数的返回值是被回收的子进程的PID
注意:wait的参数一定要写,即使不需要也要把NULL写进去,否则返回值会已一直是 -1,因为出错了。
2、waitpid()函数
waitpid函数,会暂时停止目前进程的执行,直到有信号来到或子进程结束,所以可以用来等待某个特定进程的结束。
#include<sys/types.h>
#include<sys/wait.h>
pid_t waitpid(pid_t pid, int *stat_loc, int options);
参数PID
指定需要等待的子进程PID,若它的值为-1则返回任一子进程的信息,于是在这一功能方面waitpid与wait等效。
参数 stat_loc
与wait一样如果stat_loc不是空指针,waitpid将把状态信息写到它所指向的位置。
参数 options
可用来改变waitpid的行为,其中最有用的一个选项为:WNOHANG,其作用是防止waitpid将调用者的执行挂起,若pid指定的子进程没有结束,不予以等待,立即返回,返回值为0,;若结束,则返回该子进程的PID。
在父进程不打算阻塞等待子进程返回时,可以使用这个参数,父进程可使用循环定期查询子进程的状态。
若waitpid()失败,它将返回 -1。失败原因有:没有子进程、调用被某个信号中断、选项参数无效。
如果我们不想使用这个参数,也可以把options设为0。
如:waitpid(-1, &status, 0);
wait与waitpid区别:
1. 在一个子进程终止前, wait使其调用者阻塞,而waitpid有一选择项,可使调用者不阻塞。
2. waitpid并不等待第一个终止的子进程—它有若干个选择项,可以控制它所等待的特定进程。
3. 实际上wait函数是waitpid函数的一个特例。waitpid(-1,&status, 0);