如何从父进程将信号重定向到子进程?

时间:2018-03-16 20:29:38

标签: c shell process signals fork

我正在尝试理解C中的进程。我当前想要创建类似shell的结构 - 按下 Ctrl + C 之后的快捷键 + Z 会杀死它的所有子进程,但会保持活着状态。我的代码如下所示:

#include <ctype.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/signal.h>

pid_t pid;

void send_signal(int signum){
  kill(pid, signum);
}

void init_signals(){
  signal(SIGINT, send_signal);
  signal(SIGTSTP, send_signal);
}

int main(){
    init_signals();
    pid = fork();
  if(pid > 0){
    //Parent Process
    wait(NULL);
  } else {
    // Child Process
    while(1){
        usleep(300000);
    }   

  }

  return 0;
}

问题在于,当我按下Ctrl + C时,父级会将其重定向到子级并将其杀死,但是当我按下Ctrl + Z时(即使子进程已停止),父级仍会挂起wait(NULL)。有关如何解决此问题的任何建议吗?

2 个答案:

答案 0 :(得分:1)

您可以在此处查看how to use wait in C。长话短说:

  

wait system-call将进程置于休眠状态并等待子进程结束。然后它使用子进程的退出代码填充参数(如果参数不是NULL)。

wait在子进程结束之前不会发出信号,因此只需将子进程发送到睡眠状态,主进程就没有理由继续进行。如果你想要任何主要过程仍在工作的设置,而孩子也一样(包括睡觉时),你不能等待孩子。

对于shell来说也没有意义 - 它总是在后台活动。相反,你需要一个更好的主要处理程序 - 比如等待一个条件。这样,当孩子入睡时,你可以发出信号并继续前进。

答案 1 :(得分:0)

除了https://stackoverflow.com/a/49346549/5694959的解决方案之外,我想建议另外一个解决方案来处理仅用于父进程的信号。这样父进程将执行信号处理程序,并且将对子进程执行默认操作。使用waitpid()获取孩子的状态。

  

waitpid(pid,NULL,WUNTRACED);

现在,当子进程更改其状态(即终止或停止)时,父进程将恢复执行。

按如下方式更新您的代码:

#include <ctype.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/signal.h>

pid_t pid;

void send_signal(int signum){
  kill(pid, signum);
}

void init_signals(){
  signal(SIGINT, send_signal);
  signal(SIGTSTP, send_signal);
}

int main(){

    pid = fork();
  if(pid > 0){
    //Parent Process
    init_signals();
    waitpid(pid, NULL, WUNTRACED);
    printf("I think this is what you are expecting...\n");
  } else {
    // Child Process
    while(1){
        usleep(300000);
    }   

  }

  return 0;
}

请记住一件事,请确保父流程 在按 ctrl + c ctrl + z 之前处理了信号,否则将执行信号的默认动作对于父母也是如此。