为什么只调用一次fork会得到多个SIGCHLD?

时间:2018-12-02 14:57:51

标签: c linux process signals

我正在研究Linux中的信号,并且试图了解进程的机制。我写了这段代码:

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

void filsFini(int sig){
  printf("The Child finished\n");
}

int main(){
  pid_t pid;
  system("clear");
  if((pid=fork())==0){
    printf("Child in a break\n");
    for(;;);
  }

  printf("The father %d \n",getpid());
  system("ps -lH");
  (void) signal(SIGCHLD,filsFini);
  printf("hit a button to end\n");
  getchar();
  kill(pid,SIGINT);
  system("ps -lH");
  waitpid(pid,NULL,0);
  system("ps -lH");
  return EXIT_SUCCESS;
}

最后我得到这个结果,我有一个问题是printf("Child finished\n");被写了两次,我该如何避免呢?

2 个答案:

答案 0 :(得分:3)

您每次呼叫system("ps -lH")都会创建更多的子级,并且也会收到SIGCHLD的通知。不幸的是,没有任何方法可以控制您收到SIGCHLD通知的子进程。是全有还是全无。

对于您编写的程序,我建议您什么也不要选择:不要为SIGCHLD 安装处理程序。您可以依靠已经拥有的waitpid调用,在您直接创建的子进程完成时通知您。 system将负责为其创建的子进程调用waitpid;您不必担心它们。

SIGCHLD的全有或全无是一个麻烦,因为编写更复杂的程序需要等待子进程完成和异步I / O事件的可变组合,尤其是在涉及库的情况下可能会创建主事件循环不知道的子进程。但是不要担心,直到您到达那里为止。)

答案 1 :(得分:1)

  1. system("ps -lH");也将呼叫fork(),请参阅http://man7.org/linux/man-pages/man3/system.3.html

  2. 如果只想调用printf("Child finished\n");一次,则可以在子进程中捕获SIGINT并将其输出。

以下code可以工作:

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

void handle_SIGINT(int sig) {
  printf("The Child finished\n");
  exit(EXIT_FAILURE);
}

int main(){

  signal(SIGINT, handle_SIGINT);

  pid_t pid;
  if ((pid=fork()) == 0) {
    printf("Child in a break\n");
    for(;;)
      ;
  }

  printf("The father %d \n", getpid());
  system("ps -lH");
  printf("hit a button to end\n");
  getchar();
  kill(pid, SIGINT);
  printf("\nbefore waitpid:\n");
  system("ps -lH");
  waitpid(pid, NULL, 0);
  printf("\nafter waitpid:\n");
  system("ps -lH");

  return EXIT_SUCCESS;
}