APUE之fork两次与僵尸进程的问题
2016-01-18 11:31
453 查看
初读此书,一点不明,最终的所有的无父进程的子进程都要变为init进程的子进程,那为什么,还要fork两次解决这个僵尸进程的问题,这其中的本质原因,还是没有弄清楚,为此研究一下。
如下是书中一段源码:
再次重新认识这里面的几个概念。
zombie processes
在wiki中
On Unix and Unix-like computer operating systems, a zombie process or defunct process is a process that has completed execution (via the exit system call) but still has an entry in the process table: it is a process in the “Terminated state”.
意思大概是,在unix和类unix的计算机操作系统中,如果一个进程已经结束了(通过执行系统调用exit函数),但是仍然有一个实体存在于进程表中,那么这就是一个僵尸进程,僵尸进程实际是一种“终止状态”进程。
This occurs for child processes, where the entry is still needed to allow the parent process to read its child’s exit status: once the exit status is read via the wait system call, the zombie’s entry is removed from the process table and it is said to be “reaped”.
在子进程中通常发生,当子进程结束后,其实体需要被父进程通过系统调用wait去读取,一旦使用wait系统调用读取后,子进程的实体就被从进程表里面去除了。
A child process always first becomes a zombie before being removed from the resource table. In most cases, under normal system operation zombies are immediately waited on by their parent and then reaped by the system – processes that stay zombies for a long time are generally an error and cause a resource leak.
一个子进程通常在被从资源表中移除之前,首先成为一个僵尸进程,在大多数情况下,处于常规操作系统中,父进程将会立即等待其僵尸子进程,然后清除子进程结束状态,因为如果一个僵尸进程长时间的驻留在进程表中,会导致错误并引起资源泄露。
由上面的内容可知,僵尸进程是不可避免的,但是可以消除,即将这个僵尸进程时间窗口变小。利用wait系统调用,由父进程为子进程收尸。
our parent becomes init as soon as our real parent exits
这是需要明白的第二个概念,在最上面的程序中,当第二个子进程fork出另外一个子进程后,调用exit()结束了自己的生命,他的子进程的父进程变成了init。
还是在wiki中寻找答案:
Zombie processes should not be confused with orphan processes: an orphan process is a process that is still executing, but whose parent has died. These do not remain as zombie processes; instead, (like all orphaned processes) they are adopted by init (process ID 1), which waits on its children. The result is that a process that is both a zombie and an orphan will be reaped automatically
僵尸进程和孤立进程是有区别的,孤立进程是仍然执行的进程而其父进程已经结束。这些孤立进程不是僵尸进程,他们被init进程(进程号为1)接管,init进程将一直等待其接管的子进程。如果一个子进程结束了,但是其父进程没有使用wait系统调用来清除其结束状态并且也结束了,那么这个子进程将会变成僵尸进程和孤立进程,他将会自动清除。
按照上面的说法,孤立进程不可怕可怕的是僵尸进程。只有孤立进程会被init进程重新收养,为了避免僵尸进程,在使用wait系统调用是可以解决的,但是这是一种被动等待。如果把潜在的可能成为僵尸进程变成孤立进程是不是可以呢。
在原书中的进程fork情况是这样的:
所以将进程c变成了孤立进程,那么由init进程收养。这个问题解决了
网友对此有一段看法,
这个代码并不是通用场景的避免僵尸进程的办法,它的场景是这样的:
一个进程要创建一个进程,两个进程同时处理任务,谁也不耽误谁。如果直接用子进程充当第二个进程的角色,那么问题是这样的:如果父进程处理时间长,子进程处理时间短,那么如果父进程不 wait() 处理的话,子进程就会成为僵尸进程,但如果父进程 wait() 子进程的话,父进程就会阻塞,所有有个方法就是让自己尽快推出,任务让子进程的子进程来处理。
这个场景的 APUE 的原文描述:If we want to write a process so that it forks a child but we don’t want to wait for the child to complete and we don’t want the child to become a zombie until we terminate, the trick is to call fork twice.
如下是书中一段源码:
/* * Avoid zombie processes by calling fork twice. * APUE-2e 程序清单8-5 */ #include <unistd.h> #include <sys/wait.h> #include <stdio.h> #include <stdlib.h> int main() { pid_t pid; if( (pid = fork()) < 0 ) { printf("fork error.\n"); exit(-1); } else if(pid == 0) /* first child */ { if( (pid = fork()) < 0 ) { printf("fork error.\n"); exit(-1); } else if(pid > 0) { exit(0); } /* We're the second child; our parent becomes init as soon as our real parent exits. */ printf("second child, parent pid = %d\n", getppid()); /* ---------------handle tasks--------------- */ exit(0); } if(waitpid(pid, NULL, 0) != pid) /* wait for first child */ { printf("waitpid error.\n"); exit(1); } printf("parent, first child pid = %d\n", pid); /* ---------------handle tasks--------------- */ exit(0); }
再次重新认识这里面的几个概念。
zombie processes
在wiki中
On Unix and Unix-like computer operating systems, a zombie process or defunct process is a process that has completed execution (via the exit system call) but still has an entry in the process table: it is a process in the “Terminated state”.
意思大概是,在unix和类unix的计算机操作系统中,如果一个进程已经结束了(通过执行系统调用exit函数),但是仍然有一个实体存在于进程表中,那么这就是一个僵尸进程,僵尸进程实际是一种“终止状态”进程。
This occurs for child processes, where the entry is still needed to allow the parent process to read its child’s exit status: once the exit status is read via the wait system call, the zombie’s entry is removed from the process table and it is said to be “reaped”.
在子进程中通常发生,当子进程结束后,其实体需要被父进程通过系统调用wait去读取,一旦使用wait系统调用读取后,子进程的实体就被从进程表里面去除了。
A child process always first becomes a zombie before being removed from the resource table. In most cases, under normal system operation zombies are immediately waited on by their parent and then reaped by the system – processes that stay zombies for a long time are generally an error and cause a resource leak.
一个子进程通常在被从资源表中移除之前,首先成为一个僵尸进程,在大多数情况下,处于常规操作系统中,父进程将会立即等待其僵尸子进程,然后清除子进程结束状态,因为如果一个僵尸进程长时间的驻留在进程表中,会导致错误并引起资源泄露。
由上面的内容可知,僵尸进程是不可避免的,但是可以消除,即将这个僵尸进程时间窗口变小。利用wait系统调用,由父进程为子进程收尸。
our parent becomes init as soon as our real parent exits
这是需要明白的第二个概念,在最上面的程序中,当第二个子进程fork出另外一个子进程后,调用exit()结束了自己的生命,他的子进程的父进程变成了init。
还是在wiki中寻找答案:
Zombie processes should not be confused with orphan processes: an orphan process is a process that is still executing, but whose parent has died. These do not remain as zombie processes; instead, (like all orphaned processes) they are adopted by init (process ID 1), which waits on its children. The result is that a process that is both a zombie and an orphan will be reaped automatically
僵尸进程和孤立进程是有区别的,孤立进程是仍然执行的进程而其父进程已经结束。这些孤立进程不是僵尸进程,他们被init进程(进程号为1)接管,init进程将一直等待其接管的子进程。如果一个子进程结束了,但是其父进程没有使用wait系统调用来清除其结束状态并且也结束了,那么这个子进程将会变成僵尸进程和孤立进程,他将会自动清除。
按照上面的说法,孤立进程不可怕可怕的是僵尸进程。只有孤立进程会被init进程重新收养,为了避免僵尸进程,在使用wait系统调用是可以解决的,但是这是一种被动等待。如果把潜在的可能成为僵尸进程变成孤立进程是不是可以呢。
在原书中的进程fork情况是这样的:
所以将进程c变成了孤立进程,那么由init进程收养。这个问题解决了
网友对此有一段看法,
这个代码并不是通用场景的避免僵尸进程的办法,它的场景是这样的:
一个进程要创建一个进程,两个进程同时处理任务,谁也不耽误谁。如果直接用子进程充当第二个进程的角色,那么问题是这样的:如果父进程处理时间长,子进程处理时间短,那么如果父进程不 wait() 处理的话,子进程就会成为僵尸进程,但如果父进程 wait() 子进程的话,父进程就会阻塞,所有有个方法就是让自己尽快推出,任务让子进程的子进程来处理。
这个场景的 APUE 的原文描述:If we want to write a process so that it forks a child but we don’t want to wait for the child to complete and we don’t want the child to become a zombie until we terminate, the trick is to call fork twice.
相关文章推荐
- UITextView 限制输入文本长度
- Mockplus原型交互跟我做之2- 旋转的风车
- Mockplus原型交互跟我做之1 - 30秒做一个自动消失的消息框(Toast)
- chain.doFilter(request,response)含义
- UILabel + 导入字体
- iOS开发系列--UITableView全面解析
- Intelligence emp generator the best one
- StringBuilder、StringBuffer和String三者的联系和区别
- UITableView刷新数据reLoadData
- IOS开发UI-------button
- iOS开发技巧(系列十三:UIRefreshControl下拉刷新)
- 2016.01.04 视图控制器UIViewController
- UIRefreshControl系统下拉刷新
- UIlabel:自动换行
- 【FAQ】Jenkins上,xcpretty编译报错:invalid byte sequence in US-ASCII (ArgumentError)
- 【js】数据的轮播展示(模拟Marquee,无间断滚动内容)
- 嵌入式操作系统 《ARM System Developer's Guide》
- UIGraphicsBeginImageContext和UIGraphicsBeginImageContextWithOptions实现iOS中的截图功能
- UIControl 的基本使用方法和 Target-Action 机制
- UIScreen(屏幕)、UIWindow(画框)、UIView(画布)、didFinishLaunchingWithOptions、UIViewController各个方法的加载顺序