子进程及时知道父进程已经退出的最简单方案

 

[精彩] 子进程及时知道父进程已经退出的最简单方案/h1>


http://www.chinaunix.net 作者:yuonunix  发表于:2003-10-31 10:14:14
【发表评论】 【查看原文】 【C/C++讨论区】【关闭】
要父进程知道子进程退出,这太容易了,但是要子进程知道父进程退出,可有点麻烦。 

     父进程如果退出,子进程如何知道呢,最笨的方法,父子进程之间建立socket连接,然后建立心跳,没隔1秒测试一把,当然太笨了,通过管道,可以吗何做更加简单的方法吗nbsp;

欢迎高手提出最简单的办法


 rc_hz 回复于:2003-08-11 11:52:01

肯定不能这样实现,否则程序性能没办法保证


 yuonunix 回复于:2003-08-11 12:27:55

我目前想的方法,只有用个管道,父进程每隔一秒向管道中写,子进程接收,子进程一段时间从管道中读不到字符,就认为父进程已经退出。但是这方法实在笨,想一想,又想不出好办法。要不,在子进程中使用ps命令,这方法也很土呀。


 flw 回复于:2003-08-11 12:54:00

可以考虑在父进程退出时给子进程发送信号。SIGUSR1。


 fieryfox 回复于:2003-08-11 12:57:06

你的需求到底是什么进程退出了,子进程也会退出,此时会收到SIGTERM信号。 
如果在子进程里setpgrp,那可以用所有的IPC手段去通知子进程,flw的比较实用。


 yuonunix 回复于:2003-08-11 13:08:26

引用:原帖由 “flw”]可以考虑在父进程退出时给子进程发送信号。SIGUSR1。
 发表:

     这只能处理父进程正常退出时的情况,如果父进程不是正常退出,而是遭遇了”kill -9 进程号“退出时,父进程就来不及用SIGUSR1通知子进程,就会退出,子进程照样不知道父进程的状态改变。因而这种方法好象没有办法实现“可靠地通知子进程”。


 fieryfox 回复于:2003-08-11 13:11:30

呵呵,kill -9谁也处理不了的,只能认命。这是满门抄斩的招法。


 qjlemon 回复于:2003-08-11 13:12:38

flw的办法还是挺实用的。 
试试开个管道,子进程监视管道是否还开着。不需要实际的读写,只是监视它的状态 
或者父进程锁一个文件,子进程如果”不“能得到锁,说明父进程它老人家还健在。


 yuonunix 回复于:2003-08-11 13:15:48

引用:原帖由 “fieryfox” 发表:
你的需求到底是什么进程退出了,子进程也会退出,此时会收到SIGTERM信号。 
如果在子进程里setpgrp,那可以用所有的IPC手段去通知子进程,flw的比较实用。

      

哦,你的意思是如果父进程退出,子进程如果没有setpgrp,就会收到SIGTERM信号,是吗马上尝试一下。谢谢了!


 qjlemon 回复于:2003-08-11 13:33:29

引用:原帖由 “fieryfox” 发表:
你的需求到底是什么进程退出了,子进程也会退出,此时会收到SIGTERM信号。 
如果在子进程里setpgrp,那可以用所有的IPC手段去通知子进程,flw的比较实用。

     在BSD下试了一下似乎不中啊! 


 qjlemon 回复于:2003-08-11 13:38:03

父进程退出了,子进程也会退出br>


 qjlemon 回复于:2003-08-11 13:41:52


 yuonunix 回复于:2003-08-11 14:17:12

引用:原帖由 “yuonunix” 发表:
     

哦,你的意思是如果父进程退出,子进程如果没有setpgrp,就会收到SIGTERM信号,是吗马上尝试一下。谢谢了!
      

为了验证这一点,我编了如下程序: 
#include <signal.h>; 
#include <sys/types.h>; 
#include <unistd.h>; 
#include <stdio.h>; 
int main(void) 

   register int pid; 
   if((pid = fork())<0) 
   { 
        printf(“error/n”); 
   } 
  else if(pid!=0) 
       
  {  
    printf(“begin sub progress/n”); 
    execl(“/export/home/appsvr/tt/main1”,NULL); 
  } 
  while(1) 
 { 
  }; 

}  

启动父进程后,去查子进程信息 
ps -ef|grep main1去查,子进程的进程名称已经不是main1了,请问怎样去查子进程的信息。


 yuonunix 回复于:2003-08-11 14:23:50

引用:原帖由 “qjlemon”]
 发表:

      
父进程退出了,子进程也会退出,此时会收到SIGTERM信号。其意思是: 
父进程退出时,子进程会收到SIGTERM信号。(子进程应该能够捕捉到SIGTERM信号) 

而qjlemon的例子是:父进程退出,然后父进程捕捉SIGTERM信号,是否和fieryfox的意思不符合呀


 yuxq 回复于:2003-08-11 14:34:59

good


 gadfly 回复于:2003-08-11 14:39:12

父进程退出的时候,不会自动发送sigterm信号的。 

qjlemon的例子是正确的。信号响应函数对子进程同样有效


 yuonunix 回复于:2003-08-11 15:01:00

所以到现在为止,最简单的方法还是:     

 试试开个管道,子进程监视管道是否还开着。不需要实际的读写,只是监视它的状态  
或者父进程锁一个文件,子进程如果”不“能得到锁,说明父进程它老人家还健在。 

即,要实现准确的判断父进程状态,没有很好的方法,只能这样: 

子进程每隔一秒检查一下锁(或者管道),而无法得到通知罗。


 gadfly 回复于:2003-08-11 15:05:37

管道方式是不错, 
不过不用不时的poll。 

一般网络服务都用select监听io,加到fd_set里就好了。 

如果是其它的模式,用异步io,响应sigio信号应该是可以的。


 fieryfox 回复于:2003-08-11 15:45:15

faint,搞错了。当console了。 
既然这样,那也不需要什么IPC,用getppid监控ppid的值,什么时候为1 了,父进程就退出了。


 qjlemon 回复于:2003-08-11 15:51:18

试验通过 :)     不过这就只能循环测试了


 fieryfox 回复于:2003-08-11 15:57:58

楼主要在kill -9的情况下都行,只能这样了。如果不是-9,还可以用信号USR1一类的方法。


 yuonunix 回复于:2003-08-11 16:13:58

引用:原帖由 “fieryfox” 发表:
faint,搞错了。当console了。 
既然这样,那也不需要什么IPC,用getppid监控ppid的值,什么时候为1 了,父进程就退出了。

      

这个方法确实是所有方法中最简单的方法,如果求简单,就可以用这个了,如果求效率,可能就是如gadfly所言,用管道,然后select一把,所花的CPU应该是最小的了。


 yuonunix 回复于:2003-08-12 11:28:16

我再问个相关问题,如果C是B的子进程,B是A的子进程,C可以通过getppid知道 B 的状态,B可以通过getppid知道A的状态,那么C怎样可以知道A的状态(A是否已经退出)呢现在想到的解决办法是getppid 和 kill -USR1相结合, 

孙子直接获取祖父进程的状态,好像没有比“getppid + kill -USR1”更简单的方法,各位是否这样认为br>


 fieryfox 回复于:2003-08-12 11:46:29

你在做什么应用,怎么会有这样的需求br>


 yuonunix 回复于:2003-08-12 12:52:13

引用:原帖由 “gadfly” 发表:
父进程退出的时候,不会自动发送sigterm信号的。 

qjlemon的例子是正确的。信号响应函数对子进程同样有效
      
你这句话只对了一半,信号响应函数对子进程不是全有效的。而在上面的例子里,恰好是无效的。看完下面的就会明白。 
 Signals set to the default action (SIG_DFL) in  the  calling 
     process  image are set to the default action in the new pro- 
     cess image (see signal(3C)). 
      Signals set to be ignored (SIG_IGN) by the calling  process 
     image  are  set to be ignored by the new process image. Sig- 
     nals set to be caught by the calling process image  are  set 
     to  the  default  action  in  the  new  process  image  (see 
     signal(3HEAD)).  After a successful call to any of the  exec 
     functions, alternate signal stacks are not preserved and the 
     SA_ONSTACK flag is cleared for all signals.


 qjlemon 回复于:2003-08-12 12:55:54

你自己试一下那段代码就知道了。


 yuonunix 回复于:2003-08-12 12:57:27

引用:原帖由 “fieryfox”]你在做什么应用,怎么会有这样的需求/span>
 发表:

      
我在做点Solaris上的研究。 :)


 qjlemon 回复于:2003-08-12 12:59:19

fork和exec是有重大区别的


 yuonunix 回复于:2003-08-12 13:31:43

引用:原帖由 “qjlemon”]fork和exec是有重大区别的
 发表:

     我尝试了一下,发现如此注册的信号,的确对父亲进程和孩子进程都有效,不好意思,我混淆了exec、fork对信号的处理方式,谢谢qjlemon。


 qjlemon 回复于:2003-08-12 13:33:53

不要光看书 :)


 蓝色键盘 回复于:2003-08-12 18:34:48

这个问题以前好像有人问过。 

偶目前采用的办法是: 

在具有亲缘关系的进程之间建立无名管道。这些进程通过这些管 

道传递简单的和少量的数据(也可以传递描述字)。然后,亲缘 

关系的进程都采用select来处理管道上发生的读写条件。此时, 

不论那个进程core了,或者有人kill  

-9了。对方的进程的select读会成功返回,此时根据返回的数值 

便可判断那个进程异常了,或者被他人干掉了。 

这个方法偶一直用,觉得很好使,大家可以自己试试。


 jimyao 回复于:2003-08-13 16:04:35

对于父进程已经终止的所有进程,它们都有一个叫init的进程领养,作为它的的父进程,只需要判断,这些进程的父进程的ID是否是1就可以了。      

这个办法也行。children轮训自己的getppid()的结果,然后更具结果判断是否父亲被人干掉! 
 :twisted:


 codan 回复于:2003-08-20 18:24:44

看了关于那篇关于子进程如何知道父进程退出的帖子写了下面的代码(没有出错检测)。  
下面的代码中的子进程将处于阻塞状态,不用线程可能让子进程能进行自己的工作吗(如:子进程输出不断输出一个字符’a’,同时又观察父进程状态)nbsp; 


 gadfly 回复于:2003-08-21 21:18:38

子进程可以定时去读呀。 

或者循环的时候,在某个特定的时候检查。 

如果是监听socket连接上的数据,也可以select来监听。


 superchao 回复于:2003-10-30 18:44:05

首先子进程使用getppid可以知道父进程的PID, 
使用kill ( PID, 0)如果返回<0则说明父进程不在了! 
或者判断getppid()返回的是否初始化进程的进程号1, 
如果是,则说明父进程不在了


 superchao 回复于:2003-10-30 19:30:13

还是使用kill ( 父进程号,0)判断吧,


 flyingbear 回复于:2003-10-30 20:12:08

getppid 
如果父进程退出,则结果将 = 1.这个方案不知道有什么漏洞没


 qjlemon 回复于:2003-10-31 07:51:38

这个时候ppid=1是正确的,因为该进程的父进程确确实实就是1号进程。 
———一个进程的父进程并不是永远不变的。


 hbczjzc 回复于:2003-10-31 09:55:44

第一部分–基本知识   
一.进程概念: 

进程定义了一计算的基本单位,是一个执行某一特定程序的实体.它拥有自己的地址空间,执行堆栈,文件描述符表等。 

二.创建进程: 

1.fork()函数原型 
#include <sys/types.h>; 
#include <unistd.h>; 
pid_t fork(viod); 

2.返回值 
子进程为0,父进程为子进程id,出错为-1. 

3.fork()函数用法 

两个用法: 
  一个父进程通过复制自己,使父子进程同时执行不同的代码段.这对网络服务进程是常见的:父进程等待客户的服务请求.当这种请求到达时,父进程调用fork() 
函数,使子进程处理此请求.父进程则继续等待下一个客户服务请求. 
  每个进程要执行不同的程序,这会shell是常见的,在这种情况下,子进程在从fork()函数返回后立即调用exec()函数执行其他程序. 

用法: 
#include <sys/types.h>; 
#include <unistd.h>; 
main() 

pid_t pid; 

if((pid=fork())>;0) 

/*parent process*/ 

else if(pid==0) 

/*child process*/ 
exit(0); 

else 

printf(“fork error/n”); 
eixt(0); 

4.进程终止 
   两种可能 
–父进程先于子进程终止. 
所有子进程的父进程改变为init进程称为进程由init进程领养. 

–子进程先于父进程终止. 
父进程调用wait()函数或者waitpid()函数可以得到子进程的进程id,进程的终止状态,以及进程使用的cpu时间总量. 
  

  进程正常或者异常终止,系统内核就向其父进程发送SIGCHLD信号. 

5.进程终止调用的函数 

1.wait()函数 
等待子进程返回并修改状态 
#include <sys/types.h>; 
#include <sys/wait.h>; 
pid_t wait(int *stat_loc); 
允许调用进程取得子进程的状态信息。调用进程将会挂起直到其一个子进程终止. 
返回值为该子进程进程号,否则返回-1,同时stat_loc返回子进程的返回值. 
用法: 
#include <sys/type.h>; 
#include <sys/wait.h>; 
main() 

pid_t pid; 
if ((pid=fork())>;0) 

/*parent process*/ 
int child_status; 
wait(&child_status); 

else if(pid==0) 

/*child process*/ 
exit(0); 

else 

printf(“fork error/n”); 
exit(0); 

2.waitpid()函数 
等待指定进程的子进程返回,并修改状态. 
#include <sys/types.h>; 
#include <sys/wait.h>; 
pid_t waitpid(pid_t pid,int *stat_loc,int options); 
当pid等于-1,options等于0时,该函数等同于wait()函数。 

否则该函数的行为由参数pid和options决定。 
pid指定了父进程要求知道那些子进程的状态,其中: 
=-1 要求知道任何一个子进程的返回状态; 
>;0 要求知道进程号为pid的子进程的状态; 
<-1 要求知道进程组号为pid的绝对值的子进程的状态. 

options参数为以位方式表示的标志,它是各个标志以“或”运算组成的位图,每个标志以字节中某个位置1表示: 

WUNTRACED 报告任何未知但已停止运行的指定进程的子进程状态,该进程的状态自停止运行时起就没有被报告过. 

WCONTINUED 报告任何继续运行的指定进程的子进程状态,该子进程的状态自继续运行起就没有被报告过 

WNONANG 若调用本函数时,指定进程的子进程状态,目前并不是立即有效的(即可被立即读取的),调用进程不被挂起执行。 

WNOWAIT 保持那些将其状态设置在stat_loc()函数的进程处于可等待状态,该进程将直到下次被要求其返回状态值. 

返回值为该子进程号,否则为-1,同时stat_loc()函数返回子进程的返回值 
用法: 

#include <sys/types.h>; 
#include <sys/wait.h>; 
main() 

pid_t pid; 
if ((pid=fork())>;0) 

/*parent process*/ 
int child_status; 
pid_t child_status; 
waitpid(child_pid,&child_status,0); 

else if (pid==0) 

/*child process*/ 
exit(0); 

else 

printf(“fork error”); 
exit(0); 

exit()函数 
终止进程,并返回状态。 
#include<stdlib.h>; 
viod eixt(int status); 
函数终止调用进程,exit()函数会关闭所有进程打开的描述符,向其父进程发送 SIGCHLD信号,并返回状态,父进程可通过调用wait()或者waitpid()函数获得其状态 

第二部分–多进程80banner扫描器的具体实现 

一.思路: 

1.多ip处理模块 
利用strtok()函数来分离ip 
strtok(ip,”.”); 
for来循环ip 

2.usage提示模块 
int usage(char *pro) 

printf(“fork 80 banner scanner”); 
printf(“usage:%s [startip] [stopip]/n”,pro); 

3.扫描模块 
viod scanip(char sip[20]) 

4.多进程及处理模块 
fork() 

二.实现 

/******************************************************************** 
**fork() 80 banner scanner ver1.0 

*to complie: 
*user$gcc -o 80scaner 80scanner.c 

*to use: 
*user$./80scanner start_ip stop_ip (the best input c class ip otherwise *waste too many system resource ) 

*coded by nightcat 
*june 2003 

*********************************************************************/ 
/*所要的文件*/ 
#include <sys/types.h>; 
#include <sys/wait.h>; 
#include <stdio.h>; 
#include <string.h>; 
#include <sys/socket.h>; 
#include <netinet/in.h>; 
#include <errno.h>; 
#include <netdb.h>; 
#include <signal.h>; 

/*声明函数*/ 
int usage(char *pro); 
void scanip(char *sip); 

int main(int argc,char *argv[]) 

/*声明变量*/ 
int child_status; 
pid_t child_id; 
pid_t pid; 
char *pro; 
int count; 

char *start_ip,*stop_ip; 

char *chge; 
char scan_ip[20]; 

int ip1,ip2,ip3,ip4; 
int end1,end2,end3,end4; 

/*输入参数判断*/ 
if(argc<3){ 
usage(argv[0]); 
exit(1); 

/*处理ip*/ 
start_ip=argv[1]; 
chge=strtok(start_ip,”.”); 
ip1=atoi(chge); 
chge=strtok(NULL,”.”); 
ip2=atoi(chge); 
chge=strtok(NULL,”.”); 
ip3=atoi(chge); 
chge=strtok(NULL,”.”); 
ip4=atoi(chge); 

stop_ip=argv[2]; 
chge=strtok(stop_ip,”.”); 
end1=atoi(chge); 
chge=strtok(NULL,”.”); 
end2=atoi(chge); 
chge=strtok(NULL,”.”); 
end3=atoi(chge); 
chge=strtok(NULL,”.”); 
end4=atoi(chge); 

/*循环扫描*/ 
for(count=ip4;count<=end4;count++){ 
sprintf(scan_ip,”%d.%d.%d.%d”,ip1,ip2,ip3,count); 
/*产生进程*/ 
if((pid=fork())==0){ 
scanip(scan_ip); 
exit(0); 


/*用法函数*/ 
int  usage(char *pro){ 
printf(“fork() 80 banner scanner/n”); 
printf(“input c class ip”); 
printf(“usage:%s [start_ip][stop_ip]/n”,pro); 

/*扫描函数*/ 
void scanip(char sip[20]){ 
struct sockaddr_in addr; 
int s; 
char buffer[1024]; 
if((s=socket(AF_INET,SOCK_STREAM,0))<0){ 
perror(“socket error/n”); 
exit(1); 

addr.sin_family=AF_INET; 
addr.sin_addr.s_addr=inet_addr(sip); 
addr.sin_port=htons(80); 
if(connect(s,(struct sockaddr *)&addr,sizeof(addr))<0){ 
perror(“connect error”); 
exit(1); 

send(s,”HEAD / HTTP/1.0/n/n”,17,0); 
recv(s,buffer,sizeof(buffer),0); 
printf(“%s’s http version:/n%s”,sip,buffer); 
close(s); 
sleep(5); 
exit(0); 

三.总结: 

调试的问题: 

1.sprintf(scan_ip,”%d.%d.%d.%d”,ip1,ip2,ip3,count);这条语句提示溢出,主要是scan_ip分配的内存空间不够,由原来char *scan_ip 改为char scan_ip[20] 
问题解决 

2.send(s,”HEAD / HTTP/1.0/n/n”,17,0);这条语句发送后没有得到回归的信息,只要是HTTP/1.0少了两个回车/n/n,加上就可以啦! 

其中新学的东西有: 
   1.ip的处理方法 
   2.多进程的使用方法


 hbczjzc 回复于:2003-10-31 10:05:09

1. Process Control 进程控制  
1.1 Creating new processes: fork() 创建新进程:fork函数  
1.1.1 What does fork() donbsp;fork函数干什么nbsp; 
1.1.2 What’s the difference between fork() and vfork()nbsp;fork函数 与 vfork函数的区别在哪里nbsp; 
1.1.3 Why use _exit rather than exit in the child branch of a forknbsp;为何在一个fork的子进程分支中使用_exit函数而不使用exit函数nbsp; 
1.2 Environment variables 环境变量  
1.2.1 How can I get/set an environment variable from a programnbsp;我怎样在程序中获得/设置环境变量nbsp; 
1.2.2 How can I read the whole environmentnbsp;我怎样读取整个环境变量表nbsp; 
1.3 How can I sleep for less than a secondnbsp;我怎样睡眠小于一秒nbsp; 
1.4 How can I get a finer-grained version of alarm()nbsp;我怎样得到一个更细分时间单位的alarm函数版本(译者注:希望alarm的时间小于一秒)nbsp; 
1.5 How can a parent and child process communicatenbsp;父子进程如何通信nbsp; 
1.6 How do I get rid of zombie processesnbsp;我怎样去除僵死进程nbsp; 
1.6.1 What is a zombienbsp;何为僵死进程nbsp; 
1.6.2 How do I prevent them from occuringnbsp;我怎样避免它们的出现nbsp; 
1.7 How do I get my program to act like a daemonnbsp;我怎样使我的程序作为守护程序运行nbsp; 
1.8 How can I look at process in the system like ps doesnbsp;我怎样象ps程序一样审视系统的进程nbsp; 
1.9 Given a pid, how can I tell if it’s a running programnbsp;给定一个进程号(译者注:pid: process ID),我怎样知道它是个正在运行的程序nbsp; 
1.10 What’s the return value of system/pclose/waitpidnbsp;system函数,pclose函数,waitpid函数 的返回值是什么nbsp; 
1.11 How do I find out about a process’ memory usagenbsp;我怎样找出一个进程的存储器使用情况nbsp; 
1.12 Why do processes never decrease in sizenbsp;为什么进程的大小不缩减nbsp; 
1.13 How do I change the name of my program (as seen by ****ps’)nbsp;我怎样改变我程序的名字(即“ps”看到的名字)nbsp; 
1.14 How can I find a process’ executable filenbsp;我怎样找到进程的相应可执行文件nbsp; 
1.14.1 So where do I put my configuration files thennbsp;那么,我把配置文件放在哪里呢nbsp; 
1.15 Why doesn’t my process get SIGHUP when its parent diesnbsp;为何父进程死时,我的进程未得到SIGHUP信号nbsp; 
1.16 How can I kill all descendents of a processnbsp;我怎样杀死一个进程的所有派生进程nbsp; 

2. General File handling (including pipes and sockets) 一般文件操作(包括管道和套接字)  
2.1 How to manage multiple connectionsnbsp;怎样管理多个连接nbsp;&n

来源:横云断岭

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2010年9月2日
下一篇 2010年9月4日

相关推荐