26.Linux/Unix 系统编程手册(上) -- 监控子进程

1.等待子进程
	系统调用 wait() 执行如下动作:
	1.如果调用进程并无之前未被等待的子进程终止,调用将一直阻塞,直到某个子进程终止。
	  如果调用时已有子进程终止,wait() 则立即返回。
	2.如果 status 非空,那么关于子进程如何终止的信息则会通过 status 指向的整型变量返回。
	3.内核将会为父进程下所有子进程的运行总量追加进程 cpu 时间以及资源使用数据。
	4.将终止子进程的ID作为 wait() 的结果返回。

2.waidpid(pid_t pid, int *status, int options)
	1.如果 pid > 0, 表示等待进程ID 为 pid 的子进程
	2.如果 pid = 0, 则等待与调用进程(父进程)同一个进程组的所有子进程
	3.如果 pid < -1, 则会等待进程组标识符与 pid 绝对值相等的所有子进程
	4.如果 pid = -1, 则会等待任意子进程。

3.waitid();
	waitid() 与 waitpid() 最显著的区别在于,对于应等待的子进程事件,waitid() 可以更为精准的控制。

4.wait3(),wait4()
	wait3, wait4 执行与 waitpid 类似的工作。主要语义区别在于, wait3 和 wait4 在参数 rusage 所指向的结构中
  返回终止子进程的资源使用情况。


5.孤儿进程与僵尸进程
	父进程与子进程的生命周期一般不同,所以引出2个问题:
	1.谁会是孤儿进程的父进程? 进程 ID 为 1 init 会接管孤儿进程。换言之,某一子进程调用 getppid() 返回1,
	  可以判断父进程是否存在。
	2.父进程在执行 wait 之前,子进程已经终止。系统仍然允许父进程调用 wait 获取该子进程是如何终止的。内核通过
	  将子进程转化为僵尸进程来处理这种情况。这也意味着将释放子进程所把持的大部分资源,以便其他进程重新使用。该进程所
	  唯一保留的便是内核进程表中的一条记录,其中包含了子进程的ID,终止状态,资源使用数据等。
	  如果父进程未使用 wait 而退出,那么 init 进程将接管子进程并自动调用 wait,从而从系统中移除僵尸进程。

	  如果父进程创建了一个子进程,但并未执行 wait,那么在内核的进程表中将为该子进程永远保留一条记录。如果存在大量此类僵尸进程,
	那么它们势必将填满内核进程表,从而阻碍新进程的创建。唯一的方法是,杀掉它们的父进程,此时 init 进程会接管和等待这些僵尸进程,
	从而从系统中将它们清楚。
	  在设计长生命周期的父进程,父进程应该执行 wait 方法,以确保系统总是能够清楚那些死去的子进程,避免成为长寿僵尸。

6.SIGCHLD 信号
	无论一个子进程何时终止,系统都会向其父进程发送 SIGCHLD 信号。
	如果相继有2个子进程终止,即产生了2次 SIGCHLD 信号,父进程也只能捕获一次。结束是,父进程的 SIGCHILD 信号处理程序每次只调用
  一次 wait(), 那么一些僵尸进程将成为漏网之鱼。
    解决方案:
    	在 SIGCHILD 处理程序内部循环以 WNOHANG 标志来调用 waitpid() ,直至再无其他终止子进程需要处理为止。
    	while( waitpid(-1, NULL, WNOHANG) > 0 )
    		continue;
    	上述循环会一直持续,直到 waitpid() 返回0,表明再无僵尸子进程存在。

猜你喜欢

转载自blog.csdn.net/enlyhua/article/details/82919668