为什么我的 sig_int() 函数无法阻止我的函数在 c 中退出?

问题描述 投票:0回答:2

代码如下,与书本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
信号并在按下我在 archlinux 上测试的 Ctrl+c 后立即退出。

c unix
2个回答
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 文档

24.2.2 终止信号

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

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

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

...

宏:int SIGINT

当用户键入时发送

SIGINT
(“程序中断”)信号 INTR 字符(通常为 C-c)。

处理程序 glibc 文档中的终止指出:

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()
之间可能存在显着差异。请参阅sigaction 和 signal 有什么区别?

最后,使用信号处理程序调用

printf()
是未定义的行为。只有异步信号安全函数才能从信号处理程序中安全地调用。请参阅 POSIX 2.4 信号概念 了解详细信息。


0
投票

我在学习apue的时候也遇到过这个问题,我觉得可能是

apue.h
的问题,因为我把这个头文件去掉,加上程序需要的头文件后,程序就可以正常运行了,大概是这样:

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

#define MAXLINE 4096

static void sig_int(int);

int main(int argc, char* argv[])
{
    char buf[MAXLINE];
    pid_t pid;
    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*)0);
            //err_ret("couldn't execute: %s", buf);
            exit(127);
        }
        if (pid = waitpid(pid, &status, 0) < 0) {
            //err_sys("waitpid error");
        }
        printf("%% ");
    }
    exit(0);
}

void sig_int(int signo)
{
    printf("interrupt\n%% ");
}

这个程序大致可以得到想要的结果

© www.soinside.com 2019 - 2024. All rights reserved.