execl函数后,fork子进程退出不响应SIGCHLD信号处理函数

时间:2022-02-12 22:33:47
以下代码中,fork后,在子进程中利用execl函数拉起test可执行程序执行。在fork之前设置SIGCHLD信号的处理函数为sigHandle,但是编译运行时,却发现根本不会进入到SIGCHLD信号处理函数中,很是疑惑,难道子进程退出的时候对僵尸进程已经处理了?还是说execl函数会将SIGCHLD信号处理??

execl函数后,fork子进程退出不响应SIGCHLD信号处理函数
求解。。。


#include ......  
   
pid_t cpid;  
  
 void sigHandle(int sig)  
{  
  printf("\nin sigHandle\n");  
  pid_t pid;  
  
 pid= waitpid(-1,NULL,0);  
 if (pid>0)  
 printf("pid=[%d] terminated\n",pid);  
 else  
 printf("waitpid error [%s]\n",strerror(errno));  
  return ;  
}  
int main()  
{  
  
char path[]="/home/test";  
char pro_name[]="test";  
pid_t pid;  
  
 signal(SIGCHLD,sigHandle);  
pid=fork();  
  
if(pid==0)  
{cpid=getpid();  
  printf("cpid=[%d]\n",cpid);  
  if( 0 > execl(path,pro_name,par,"start",NULL))  
 // if( 0 > system(path))   
{  
  printf("call program: [%s] failed!\n",pro_name);  
  }// sleep(1); //此处加上后SIGCHLD信号处理函数怎么不执行了呢??  
printf("\nnever run here \n");  
}  
 return 0;  
}

12 个解决方案

#1


man execl函数, 有以下说明:
Signals set to the default action (SIG_DFL) in the calling process image shall be set to the default action in  the   new  process  image.  Except for SIGCHLD, signals set to be ignored (SIG_IGN) by the calling process image shall be set to be ignored by the new process image.  Signals set to be caught by the calling process image shall be  set  to the  default  action  in  the new process image (see <signal.h>).

是不是因为这个原因呢? execl函数后,fork子进程退出不响应SIGCHLD信号处理函数

#2


execl函数后,fork子进程退出不响应SIGCHLD信号处理函数

#3


自己进行了以下实验:
test.c中:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
  printf("\ntest:\n test pid=[%d],ppid=[%d]\n",getpid(), getppid());
  sleep(1);
  return 0;
}


exec.c中:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <errno.h>
pid_t cpid;

void sigHandle(int sig)
{
  printf("\n************in sigHandle*************\n");
  pid_t pid;  

  pid= waitpid(-1,NULL,0);

 if (pid>0)
     printf("pid=[%d] terminated\n",pid);
 else
     printf("waitpid error [%s]\n",strerror(errno));
  return ;
}

int main()
{

char path[]="/Desktop/MyTest/test";
char pro_name[]="test";
pid_t pid;

// signal(SIGCHLD,sigHandle);
struct sigaction chld;
memset(&chld,0x00,sizeof(chld));
chld.sa_handler=sigHandle;
sigaction(SIGCHLD,&chld,NULL);

pid=fork();

if(pid==0)
{

  cpid=getpid();
  printf("\nexec:This is in child process. \nchild pid=[%d] ,father pid =[%d]\n",cpid,getppid());
  if( 0 > execl(path,pro_name,NULL))
 // if( 0 > system(path))  
  {/*调起任务失败*/
    printf("call program: [%s] failed!\n",pro_name);
  }
  printf("\nnever run here\n");
}
else
if (pid>0)
{
  printf("exec:in father process.\n pid=[%d]\n",getpid());
  sleep(5);//此处加入了等待子进程结束
   ;
}
return 0;
}


程序运行结果:
 
execl函数后,fork子进程退出不响应SIGCHLD信号处理函数

但是如果将exec.c中的父进程中的sleep(5)去掉,则执行结果为:

execl函数后,fork子进程退出不响应SIGCHLD信号处理函数
Fork分叉后,先执行父进程,父进程执行完毕后直接返回了。而在执行子进程时,由于父进程已经退出所以此时father pid已经变为(init )1号进程了。
总归是由于父子进程的竞争执行顺序关系影响了SIGCHLD信号处理函数的执行。

#4



事实是父进程fork()没有阻塞等待SIGCHLD,就直接return 0了,然后子进程变成了zombie

#5


你在return 0前加个 pause();

#6


引用 5 楼 Vegertar 的回复:
你在return 0前加个 pause();


厉害! execl函数后,fork子进程退出不响应SIGCHLD信号处理函数

#7


引用 5 楼 Vegertar 的回复:
你在return 0前加个 pause();

为啥我ps命令查看,没有看到僵尸进程呢?? execl函数后,fork子进程退出不响应SIGCHLD信号处理函数

#8


pause方案不够专业。

了解一下sigprocmask+sigsuspend

#9


引用 7 楼 why_ny 的回复:
Quote: 引用 5 楼 Vegertar 的回复:

你在return 0前加个 pause();

为啥我ps命令查看,没有看到僵尸进程呢?? execl函数后,fork子进程退出不响应SIGCHLD信号处理函数


嗯,过继到init了,没有zombie。不好意思。

#10


引用 8 楼 qq120848369 的回复:
pause方案不够专业。

了解一下sigprocmask+sigsuspend


恩,如果我程序里面fork了多个子进程,每个子进程通过execl函数拉起不同的可执行程序,这样每个子进程(其实也就是每个execl函数拉起的每个可执行程序)结束的时间并不一定相同,这样的话如果在父进程return之前pause() 一下,就只能接收到在调用pause()函数这一时刻时结束的子进程发出的SIGCHLD信号,处理僵尸进程。万一有个子进程执行的时间比较长,在pause()这一时刻还没有结束,而这时父进程已经返回了,那岂不是这个子进程就成为僵尸进程了吗??
这种情况下应该怎么办呢?怎么将所有子进程产生的僵尸进程全部清理了呢??

#11


你想做的其实就是wait所有的子进程。
可以对waited子进程和total子进程数都做记录,如果不相等就通过某种方式阻塞,然后再wait,直到回收了所有子进程为止。

#12


引用 11 楼 Vegertar 的回复:
你想做的其实就是wait所有的子进程。
可以对waited子进程和total子进程数都做记录,如果不相等就通过某种方式阻塞,然后再wait,直到回收了所有子进程为止。

恩,这个方法我倒是想到了,在fork的时候记录下所有的子进程数,然后看wait了多少个,进行判断。
但是想知道还有没有其他的方法。 execl函数后,fork子进程退出不响应SIGCHLD信号处理函数

#1


man execl函数, 有以下说明:
Signals set to the default action (SIG_DFL) in the calling process image shall be set to the default action in  the   new  process  image.  Except for SIGCHLD, signals set to be ignored (SIG_IGN) by the calling process image shall be set to be ignored by the new process image.  Signals set to be caught by the calling process image shall be  set  to the  default  action  in  the new process image (see <signal.h>).

是不是因为这个原因呢? execl函数后,fork子进程退出不响应SIGCHLD信号处理函数

#2


execl函数后,fork子进程退出不响应SIGCHLD信号处理函数

#3


自己进行了以下实验:
test.c中:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
  printf("\ntest:\n test pid=[%d],ppid=[%d]\n",getpid(), getppid());
  sleep(1);
  return 0;
}


exec.c中:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <errno.h>
pid_t cpid;

void sigHandle(int sig)
{
  printf("\n************in sigHandle*************\n");
  pid_t pid;  

  pid= waitpid(-1,NULL,0);

 if (pid>0)
     printf("pid=[%d] terminated\n",pid);
 else
     printf("waitpid error [%s]\n",strerror(errno));
  return ;
}

int main()
{

char path[]="/Desktop/MyTest/test";
char pro_name[]="test";
pid_t pid;

// signal(SIGCHLD,sigHandle);
struct sigaction chld;
memset(&chld,0x00,sizeof(chld));
chld.sa_handler=sigHandle;
sigaction(SIGCHLD,&chld,NULL);

pid=fork();

if(pid==0)
{

  cpid=getpid();
  printf("\nexec:This is in child process. \nchild pid=[%d] ,father pid =[%d]\n",cpid,getppid());
  if( 0 > execl(path,pro_name,NULL))
 // if( 0 > system(path))  
  {/*调起任务失败*/
    printf("call program: [%s] failed!\n",pro_name);
  }
  printf("\nnever run here\n");
}
else
if (pid>0)
{
  printf("exec:in father process.\n pid=[%d]\n",getpid());
  sleep(5);//此处加入了等待子进程结束
   ;
}
return 0;
}


程序运行结果:
 
execl函数后,fork子进程退出不响应SIGCHLD信号处理函数

但是如果将exec.c中的父进程中的sleep(5)去掉,则执行结果为:

execl函数后,fork子进程退出不响应SIGCHLD信号处理函数
Fork分叉后,先执行父进程,父进程执行完毕后直接返回了。而在执行子进程时,由于父进程已经退出所以此时father pid已经变为(init )1号进程了。
总归是由于父子进程的竞争执行顺序关系影响了SIGCHLD信号处理函数的执行。

#4



事实是父进程fork()没有阻塞等待SIGCHLD,就直接return 0了,然后子进程变成了zombie

#5


你在return 0前加个 pause();

#6


引用 5 楼 Vegertar 的回复:
你在return 0前加个 pause();


厉害! execl函数后,fork子进程退出不响应SIGCHLD信号处理函数

#7


引用 5 楼 Vegertar 的回复:
你在return 0前加个 pause();

为啥我ps命令查看,没有看到僵尸进程呢?? execl函数后,fork子进程退出不响应SIGCHLD信号处理函数

#8


pause方案不够专业。

了解一下sigprocmask+sigsuspend

#9


引用 7 楼 why_ny 的回复:
Quote: 引用 5 楼 Vegertar 的回复:

你在return 0前加个 pause();

为啥我ps命令查看,没有看到僵尸进程呢?? execl函数后,fork子进程退出不响应SIGCHLD信号处理函数


嗯,过继到init了,没有zombie。不好意思。

#10


引用 8 楼 qq120848369 的回复:
pause方案不够专业。

了解一下sigprocmask+sigsuspend


恩,如果我程序里面fork了多个子进程,每个子进程通过execl函数拉起不同的可执行程序,这样每个子进程(其实也就是每个execl函数拉起的每个可执行程序)结束的时间并不一定相同,这样的话如果在父进程return之前pause() 一下,就只能接收到在调用pause()函数这一时刻时结束的子进程发出的SIGCHLD信号,处理僵尸进程。万一有个子进程执行的时间比较长,在pause()这一时刻还没有结束,而这时父进程已经返回了,那岂不是这个子进程就成为僵尸进程了吗??
这种情况下应该怎么办呢?怎么将所有子进程产生的僵尸进程全部清理了呢??

#11


你想做的其实就是wait所有的子进程。
可以对waited子进程和total子进程数都做记录,如果不相等就通过某种方式阻塞,然后再wait,直到回收了所有子进程为止。

#12


引用 11 楼 Vegertar 的回复:
你想做的其实就是wait所有的子进程。
可以对waited子进程和total子进程数都做记录,如果不相等就通过某种方式阻塞,然后再wait,直到回收了所有子进程为止。

恩,这个方法我倒是想到了,在fork的时候记录下所有的子进程数,然后看wait了多少个,进行判断。
但是想知道还有没有其他的方法。 execl函数后,fork子进程退出不响应SIGCHLD信号处理函数