已处理的 SIGINT 是否会影响与子进程的管道通信?

已处理的 SIGINT 是否会影响与子进程的管道通信?

我有一个交互式 C 程序,它从终端读取一个短语,并计算一系列字谜。我还有一个 Perl 程序,它从 STDIN 读取和缓冲行,直到收到保留的“输入结束”标记,对行进行排序,将它们组织成列并将它们发送到 STDOUT。 C 程序使用 BSD/MacOSpopen()通过单个双向管道启动 Perl 程序,并fprintf()在管道上进行 anagrams,直到生成所有 anagrams;发送“输入结束”标记,然后getline()在管道上发出 来读回并打印格式化结果。

正常情况下工作正常。但我向 C 程序添加了一个 SIGINT 处理程序,这样我就可以中断长时间运行的字谜,打印迄今为止的任何结果,并循环获取更多终端输入。处理程序设置一个标志,主程序在写入管道后检查该标志。如果已设置,它将跳出字谜循环并继续进行,就像循环自然结束一样:它发送输入结束字符串,并读回格式化结果。

它爆发了,没问题;fprintf输入结束得到正常的返回码;但第一个getline返回一个指示 EOF 的空指针,所以我没有得到任何部分结果。 C 程序按预期正常继续。

我在文档中没有找到任何内容表明已处理的 SIGINT 会影响任何打开的管道,但我想不出还有什么会阻止我从 Perl 程序接收任何内容。

答案1

信号SIGINT发送到前台进程组中的每个进程;前台进程组通常包括任何 popen运行,

/* popen.c */
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void poke(int unused) { fprintf(stderr, "sigint - C\n"); }
int main(void) {
    FILE *fh;
    signal(SIGINT, poke);
    fh = popen(
      "exec perl -e '$SIG{INT}=sub {warn q{ouch}};sleep 1 while 1'",
      "r+");
    if (!fh) abort();
    while (1) sleep(1);
    return 42;
}

可以通过以下方式验证:

$ make popen
$ ./popen
^Csigint - C
ouch at -e line 1.
^Csigint - C
ouch at -e line 1.
^\Quit

因此,所有程序都必须处理该信号,或者可以在终端中关闭该信号。详细信息因语言而异,但要忽略 Perl 中的信号,可以简单地忽略它:

$SIG{INT} = "IGNORE";

另一种选择是阻止父进程中的信号,尽管后续程序可能会安装自己的信号处理程序。

ISIG另一种选择是在终端中禁用该标志。在这种情况下control+c不会导致向前台进程组发送信号;相反,某个字符将可供某些程序读取。有关详细信息,请参阅termios手册页(手册页部分将因操作系统而异)。像curses这样的接口可能是这里的典型接口,尽管可以改为进行适当的 tcsetattr(3)调用以disable ISIG

#!/usr/bin/env perl
# example script showing how control+c can be read as a key
use strict;
use warnings;
use Curses;
initscr;
noecho;
raw;    # disables ISIG, among other things
while (1) {
    my $ch = getchar() // die "getchar failed??";
    last if $ch eq 'q';
    move 0, 0;
    clrtoeol;
    addstring sprintf "key: %vx", $ch;
}
endwin;

key: 3当按下control+时应该显示此内容;c信号不会发送到前台进程组。键入q退出。

相关内容