使用信号处理程序暂停/恢复子进程

时间:2017-10-01 04:31:38

标签: c signals signal-handling

我目前正在尝试使用它们来控制使用fork()方法创建的子进程,从而在C中试验信号。本质上,我有一个子进程从linux终端运行“yes”命令(这个命令只打印“y”和换行符直到它终止)。我希望能够使用CTRL-Z暂停/恢复此过程。这就是我现在所拥有的:

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
pid_t CHILD_PROCESS;
pid_t PARENT_PROCESS;
int isPaused;
void pause_handler(int signo){
  if(!isPaused){  
    printf("Ctrl-Z pressed. Pausing child.\n");
    isPaused = 1;
    kill(CHILD_PROCESS,SIGSTOP);
  }
  else if(isPaused){
   printf("\nCtrl-Z pressed. Resuming child.\n");
   kill(CHILD_PROCESS,SIGCONT);
   isPaused = 0;
  }
}

int main(int argc, char** argv){
  pid_t pid;
  PARENT_PROCESS = getpid();
  pid = fork();
  if(pid == 0){
    system("yes");
  }
  isPaused = 0;
  if(pid > 0){
    signal(SIGTSTP, SIG_IGN);
    signal(SIGSTOP, SIG_IGN);
    CHILD_PROCESS = pid;
    while(1){
      if(signal(SIGTSTP,pause_handler) == SIG_ERR){
        printf("Signal Failure");
      }
    }
  }
}

当我运行它时,我可以“按下Ctrl-Z。暂停孩子。”按CTRL-Z打印到控制台,我可以按“Ctrl-Z按下。恢复孩子。”再次按CTRL-Z打印到控制台。但是,它实际上并没有一遍又一遍地重新打印“y”。关于为什么子进程没有恢复的任何想法?

1 个答案:

答案 0 :(得分:3)

事实证明,system中有一个隐式的fork调用,因此存储在CHILD_PROCESS中的PID最终并不是子进程,而是中间进程。

来自man 3 system

   The  system()  library  function uses fork(2) to create a child process
   that executes the shell command specified in command using execl(3)  as
   follows:

       execl("/bin/sh", "sh", "-c", command, (char *) 0);

   system() returns after the command has been completed.

因此,如果我们用system("yes")替换execl("/bin/sh", "sh", "-c", "yes", NULL)调用,那么我们就会避免使用这个额外的fork,并且程序会根据需要运行。

唯一的另一个问题是,通过我评论我发现on this post,在信号处理程序中使用printf是未定义的行为。这里不用担心这个问题,但是为了将来的代码需要注意的事情!