为什么我的sig_int()函数不能阻止我的函数退出c?

时间:2017-09-11 08:54:34

标签: c unix

代码如下,与书中的代码相同 apue3e

#include "apue.h"
#include "sys/wait.h"

static void sig_int(int);

int
main(int argc, char *argv[]) {
  pid_t pid;
  char buf[MAXLINE];
  int status;

  if (signal(SIGINT, sig_int) == SIG_ERR) {
    err_sys("signal error");
  }

  printf("%% ");
  while (fgets(buf, MAXLINE, stdin) != NULL) {
    if (buf[strlen(buf)-1] == '\n') {
      buf[strlen(buf)-1] = '\0';
    }

    if ((pid = fork()) < 0) {
      err_sys("fork error");
    } else if (pid == 0) {
      execlp(buf, buf, (char *)NULL);
      err_ret("couldn't execlvp: %s\n", buf);
      exit(127);
    }

    if ((pid = waitpid(pid, &status, 0)) < 0) {
      err_sys("waitpid_error");
    }
    printf("%% ");
  }
  exit(0);
}

static void
sig_int(int signo/* arguments */) {
  /* code */
  printf("Interrupted\n%%3 ");
}

所以,我的问题是为什么这个信号处理程序没有处理SIGINT信号并在按 Ctrl + c 之后立即退出,我在 archlinux上测试

1 个答案:

答案 0 :(得分:2)

  

[W]这个信号处理程序没有处理SIGINT信号并在按下我在archlinux上测试的 Ctrl + c 后立即退出。

鉴于

static void
sig_int(int signo/* arguments */) {
  /* code */
  printf("Interrupted\n%%3 ");
}

signal(SIGINT, sig_int)

CTRL-C 时,您的进程不会退出,原因很简单,因为信号处理程序不会导致进程退出。

您已使用自己的处理程序替换了默认的SIGINT处理程序,因此退出该进程的默认操作不再发生。

由于您在Linux上运行,我将参考GNU glibc documentation on termination signals

  

24.2.2终止信号

     

这些信号都用于告诉进程以某种方式终止   或其他。他们有不同的名字,因为他们习惯了   目的略有不同,程序可能想要处理它们   不同。

     

处理这些信号的原因通常是您的程序可以   在实际终止之前适当整理。例如,你   可能想保存状态信息,删除临时文件或   恢复以前的终端模式。这样的处理程序应该以   指定发生的信号的默认操作然后   重新加油;这将导致程序终止   信号,就好像它没有处理程序一样。 (见Termination in Handler。)

     

所有这些信号的(明显的)默认操作是导致   终止的过程。

     

...

     

宏: int SIGINT

     

用户输入时发送SIGINT(“程序中断”)信号   INTR字符(通常是 C-c )。

Termination in Handler glibc documentation州:

  

24.4.2终止流程的处理程序

     

终止程序的处理程序函数通常用于   导致有序清理或从程序错误信号中恢复   互动中断。

     

处理程序终止进程的最简洁方法是引发   首先运行处理程序的相同信号。这是怎么回事   这样做:

volatile sig_atomic_t fatal_error_in_progress = 0;

void
fatal_error_signal (int sig)
{

  /* Since this handler is established for more than one kind of signal, 
     it might still get invoked recursively by delivery of some other kind
     of signal.  Use a static variable to keep track of that. */
  if (fatal_error_in_progress)
    raise (sig);
  fatal_error_in_progress = 1;


  /* Now do the clean up actions:
     - reset terminal modes
     - kill child processes
     - remove lock files */
  …


  /* Now reraise the signal.  We reactivate the signal’s
     default handling, which is to terminate the process.
     We could just call exit or abort,
     but reraising the signal sets the return status
     from the process correctly. */
  signal (sig, SIG_DFL);
  raise (sig);
}

另请注意,signal()sigaction()之间可能存在显着差异。见What is the difference between sigaction and signal?

最后,使用信号处理程序调用{​​{1}}是未定义的行为。只能从信号处理程序中安全地调用异步信号安全功能。有关血腥的详细信息,请参阅POSIX 2.4 Signal Concepts