wait和waitpid

wait和waitpid 2012-10-26 16:41:39
分类: LINUX
当有多个子进程的SIGCHLD信号到达父进程的时候,如果父进程用wait等待,那么父进程在处理第一个达到的SIGCHLD信号的时候,其他的SIGCHLD信号被堵塞,而且信号不被缓存,这样就会导致信号丢失,这样会产生很多的僵尸进程。。解决办法是父进程用waitpid来等待子进程信号。。。

正好看到有人问这样一个问题

看unix网络编程第一卷的时候,碰到书上这样一个例子:
一个并发服务器, 每一个客户端连接服务器就fork一个子进程.书上讲到当同时有n多个客户端断开连接时,
服务器端同时有n多个子进程终止, 这时候内核同时向父进程发送n多个sigchld信号.它的sigchld信号处理
函数如下:
void sig_chld(int signo)
{
       pid_t   pid;
       int     stat;

       while((pid = waitpid(-1, &stat, WNOHANG)) > 0){
               printf("child %d terminated\n", pid);
       }
        return;
}

我的问题是:既然sigchld是不可靠的信号,进程就不可能对sigchld进行排队, 直接丢弃了sigchld信号(当进程注册信号的时候,发现已有sigchld注册进未决信号, 因为内核同时发送多个sigchld).请问大家上面的代码是如何保证不产生僵尸进程的.谢谢!

超清晰的解答,来自与chinaunix论坛的flw大版主。。。:

根本就不需要找回来!
好比有五个进程,
不妨分别称为 p1 p2 p3 p4 p5,
一开始 p1 结束了,发了一个 SIGCHLD(s1),
这时父进程可能空闲了,于是开始处理这个信号,假设处理的过程中 p2 又结束了,又发了一个 SIGCHLD(s2),
这时候已经有两个信号了(一个正在处理,一个待处理),这时如果 p3 又结束了,那么它发的那个 SIGCHLD(s3) 势必会丢失,
丢失了怎么办?
没关系,因为那个信号处理函数是个循环嘛,
所以 while(waitpid()) 的时候,会把 p1 p2 p3 都处理的。
即使是很不幸,因为十分凑巧的原因,p3 没有被回收,导致变成僵尸进程了,也没关系,
因为还有 p4 p5 嘛,等到 p4 或者 p5 结束的时候,
又会再一次调用 while(waitpid()),到时候虽说这个 while(waitpid()) 是由 p4/p5 引起的,但是它也会一并把 p3 也处理的,因为它是个循环嘛!

如果还搞不懂,你就再看看 waitpid 的 man。

记住一点:
waitpid 和 SIGCHLD 没关系,即使是某个子进程对应的 SIGCHLD 丢失了,只要父进程在任何一个时刻调用了 waitpid,那么这个进程还是可以被回收的。

哎呀呀,简直费劲死了,其实说白了,就是一个“生产者-消费者”问题。
子进程结束的时候,系统“生产”出一个僵尸进程,
同时用 SIGCHLD 通知父进程来“消费”这个僵尸进程,
即使是 SIGCHLD 丢失了,没有来得及消费,
但是只要有一次消费,就会把所有的僵尸进程都处理光光!
(我再说一遍:因为,while(waitpid()) 是个循环嘛!)
我试了一下,wait好像也可以哦

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
  pid_t pc, pr;
  pc = fork();
  if(pc<0){
    printf("fork error\n");
  }else if(pc == 0){
        printf("child pid = %d\n", getpid());
  }else{
        pr = fork();
        if(pr == 0)
                printf("child pid = %d\n", getpid());
        else{

                printf("parent pid = %d\n", getpid());
                sleep(20);
                while((pr = wait(NULL)) != -1)
                        ;
                printf("this is parent process.\n");
                sleep(20);
        }
  }

  exit(0);
}
运行后,
程序先输出
child pid = 14478
parent pid = 14477
child pid = 14479
然后进入sleep(20);  这时候 开另一个terminal, 运行 ps auxw | grep 1447, 得到
1000     14477  0.0  0.0   4124   316 pts/3    S+   05:36   0:00 ./wait
1000     14478  0.0  0.0      0     0 pts/3    Z+   05:36   0:00 [wait] <defunct>
1000     14479  0.0  0.0      0     0 pts/3    Z+   05:36   0:00 [wait] <defunct>
1000     14499  0.0  0.0 109244   868 pts/5    S+   05:36   0:00 grep --color=auto 1447

可以看到,两个子进程已经编程僵尸进程

然后20秒后,父进程执行了wait() ,输出
child pid = 14478
parent pid = 14477
child pid = 14479
this is parent process.

这时候,到另一个终端里,再次运行ps
1000     14477  0.0  0.0   4124   316 pts/3    S+   05:36   0:00 ./wait
1000     14619  0.0  0.0 109244   872 pts/5    S+   05:37   0:00 grep --color=auto 1447

可以看到两个僵尸子进程已经被回收。。

http://blog.chinaunix.net/uid-1911213-id-3387225.html
wait和waitpid 2012-10-26 16:41:39
分类: LINUX
当有多个子进程的SIGCHLD信号到达父进程的时候,如果父进程用wait等待,那么父进程在处理第一个达到的SIGCHLD信号的时候,其他的SIGCHLD信号被堵塞,而且信号不被缓存,这样就会导致信号丢失,这样会产生很多的僵尸进程。。解决办法是父进程用waitpid来等待子进程信号。。。

正好看到有人问这样一个问题

看unix网络编程第一卷的时候,碰到书上这样一个例子:
一个并发服务器, 每一个客户端连接服务器就fork一个子进程.书上讲到当同时有n多个客户端断开连接时,
服务器端同时有n多个子进程终止, 这时候内核同时向父进程发送n多个sigchld信号.它的sigchld信号处理
函数如下:
void sig_chld(int signo)
{
       pid_t   pid;
       int     stat;

       while((pid = waitpid(-1, &stat, WNOHANG)) > 0){
               printf("child %d terminated\n", pid);
       }
        return;
}

我的问题是:既然sigchld是不可靠的信号,进程就不可能对sigchld进行排队, 直接丢弃了sigchld信号(当进程注册信号的时候,发现已有sigchld注册进未决信号, 因为内核同时发送多个sigchld).请问大家上面的代码是如何保证不产生僵尸进程的.谢谢!

超清晰的解答,来自与chinaunix论坛的flw大版主。。。:

根本就不需要找回来!
好比有五个进程,
不妨分别称为 p1 p2 p3 p4 p5,
一开始 p1 结束了,发了一个 SIGCHLD(s1),
这时父进程可能空闲了,于是开始处理这个信号,假设处理的过程中 p2 又结束了,又发了一个 SIGCHLD(s2),
这时候已经有两个信号了(一个正在处理,一个待处理),这时如果 p3 又结束了,那么它发的那个 SIGCHLD(s3) 势必会丢失,
丢失了怎么办?
没关系,因为那个信号处理函数是个循环嘛,
所以 while(waitpid()) 的时候,会把 p1 p2 p3 都处理的。
即使是很不幸,因为十分凑巧的原因,p3 没有被回收,导致变成僵尸进程了,也没关系,
因为还有 p4 p5 嘛,等到 p4 或者 p5 结束的时候,
又会再一次调用 while(waitpid()),到时候虽说这个 while(waitpid()) 是由 p4/p5 引起的,但是它也会一并把 p3 也处理的,因为它是个循环嘛!

如果还搞不懂,你就再看看 waitpid 的 man。

记住一点:
waitpid 和 SIGCHLD 没关系,即使是某个子进程对应的 SIGCHLD 丢失了,只要父进程在任何一个时刻调用了 waitpid,那么这个进程还是可以被回收的。

哎呀呀,简直费劲死了,其实说白了,就是一个“生产者-消费者”问题。
子进程结束的时候,系统“生产”出一个僵尸进程,
同时用 SIGCHLD 通知父进程来“消费”这个僵尸进程,
即使是 SIGCHLD 丢失了,没有来得及消费,
但是只要有一次消费,就会把所有的僵尸进程都处理光光!
(我再说一遍:因为,while(waitpid()) 是个循环嘛!)
我试了一下,wait好像也可以哦

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
  pid_t pc, pr;
  pc = fork();
  if(pc<0){
    printf("fork error\n");
  }else if(pc == 0){
        printf("child pid = %d\n", getpid());
  }else{
        pr = fork();
        if(pr == 0)
                printf("child pid = %d\n", getpid());
        else{

                printf("parent pid = %d\n", getpid());
                sleep(20);
                while((pr = wait(NULL)) != -1)
                        ;
                printf("this is parent process.\n");
                sleep(20);
        }
  }

  exit(0);
}
运行后,
程序先输出
child pid = 14478
parent pid = 14477
child pid = 14479
然后进入sleep(20);  这时候 开另一个terminal, 运行 ps auxw | grep 1447, 得到
1000     14477  0.0  0.0   4124   316 pts/3    S+   05:36   0:00 ./wait
1000     14478  0.0  0.0      0     0 pts/3    Z+   05:36   0:00 [wait] <defunct>
1000     14479  0.0  0.0      0     0 pts/3    Z+   05:36   0:00 [wait] <defunct>
1000     14499  0.0  0.0 109244   868 pts/5    S+   05:36   0:00 grep --color=auto 1447

可以看到,两个子进程已经编程僵尸进程

然后20秒后,父进程执行了wait() ,输出
child pid = 14478
parent pid = 14477
child pid = 14479
this is parent process.

这时候,到另一个终端里,再次运行ps
1000     14477  0.0  0.0   4124   316 pts/3    S+   05:36   0:00 ./wait
1000     14619  0.0  0.0 109244   872 pts/5    S+   05:37   0:00 grep --color=auto 1447

可以看到两个僵尸子进程已经被回收。。

http://blog.chinaunix.net/uid-1911213-id-3387225.html
时间: 2024-08-01 12:15:32

wait和waitpid的相关文章

转载:进程退出状态--waitpid status意义

最近遇到一个进程突然退出的问题,由于没有注册signalhandler所以没有捕捉到任何信号. 但是从log中看到init waitpid返回的status为0x008b,以前对status不是很了解,下面的文章对status有比较全面的介绍. 转至http://tsecer.blog.163.com/blog/static/15018172012323975152/ 一.和子进程同步在linux系统中,父进程通常需要通过waitpid来等待/获取子进程状态变化情况,而这个主要就是通过waitX

linux wait 和waitpid

背景:在读unix网络编程卷1, 第五章服务器处理SIGCHLD信号时.及多个客户端同时关闭socket连接,服务端主进程的多个子进程几乎同时结束. 使用wait 的情况: void sig_chld(int signo) { pid_t pid; int stat; pid = wait(&stat); return; } 当服务端采用并发处理客户端的请求时,客户进程关闭连接,服务端子进程几乎同时结束,信号处理函数在使用wait时,并不能完全的防止僵尸进程的出现,问题在于,信号处理函数在处理第

系统调用wait、waitpid和exec函数

本文介绍了Linux下的进程的一些概念,并着重讲解了与Linux进程管理相关的重要系统调用wait,waitpid和exec函数族,辅助一些例程说明了它们的特点和使用方法. 1.7 背景 在前面的文章中,我们已经了解了父进程和子进程的概念,并已经掌握了系统调用exit的用法,但可能很少有人意识到,在一个进程调用了exit之后,该进程并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构.在Linux进程的5种状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可

wait和waitpid详解

wait的flag参数不是很明确,考虑多个进程同时结束的情况,信号时如何处理的,是否会出现覆盖情况 wait的函数原型是: #include<sys/types.h> #include <sys/wait.h> pid_t wait(int *status) 进程一旦调用了wait,就立即阻塞自己,由wait自动分析是 否当前进程的某个子进程已经退出,如果让它找到了这样一个 已经变成僵尸的子进程, wait就会收集这个子进程的信息,并 把它彻底销毁后返回:如果没有找到这样一个子进程

详解wait和waitpid函数

#include <sys/types.h> /* 提供类型pid_t的定义 */ #include <sys/wait.h> pid_t wait(int *status) 进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回:如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止. 参数status用来保存被收集进程退出时

linux c学习笔记----进程创建(fork,wait,waitpid)

1.pid_t fork(); (1)当一个进程调用了fork 以后,系统会创建一个子进程.这个子进程和父进程不同的地方只有他的进程ID 和父进程ID,其他的都是一样.就象符进程克隆(clone)自己一样. (2)为了区分父进程和子进程,我们必须跟踪fork 的返回值. 当fork 掉用失败的时候(内存不足或者是用户的最大进程数已到)fork 返回-1,否则fork 的返回值有重要的作用.对于父进程fork 返回子进程的ID,而对于fork 子进程返回0.我 们就是根据这个返回值来区分父子进程的

waitpid传入参数

1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<unistd.h> 4 int main() 5 { 6 pid_t pid,pr; 7 pid =fork(); 8 int status; 9 if(pid<0) 10 { 11 printf("Fork failed!\n"); 12 exit(1); 13 } 14 else if(pid==0) 15 { 16 printf(&qu

wait和waitpid详解【转】

wait的函数原型是:  #include<sys/types.h> #include <sys/wait.h> pid_t wait(int *status)  进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回:如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止. 参数: 参数status用来保存被收集进程退出时的一

linux中waitpid及wait的用法【转】

wait(等待子进程中断或结束) 表头文件 #include<sys/types.h> #include<sys/wait.h> 定义函数 pid_t wait (int * status); 函数说明: wait()会暂时停止目前进程的执行,直到有信号来到或子进程结束. 如果在调用 wait()时子进程已经结束,则 wait()会立即返回子进程结束状态值. 子进程的结束状态值会由参数 status 返回,而子进程的进程识别码也会一起返回. 如果不在意结束状态值,则参数 statu

os.waitpid()无法获取sys.exit()退出时的status code

[目的] 父进程使用os.waitpid()等待子进程退出,并检测子进程的exit code,以决定是否重启子进程. (常见的应用场景是:子进程接收外部命令,收到"stop"时退出所有进程,终止服务:收到"restart"时所有子进程退出,父进程重启所有子进程,以达到重启服务的目的). 这里面的关键点在于,子进程退出时设置exit code,父进程waitpid时获取该exit code,进而决定是否需要重启子进程. [问题] 子进程 ...#need restar