奇怪的 sigaction() 和 getline() 交互

Con*_*nor 4 c signals getline signal-handling

我有一个使用 sigaction 设置的信号处理程序,如下所示:

struct sigaction act, oldact;
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = sig_handler;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, SIGALRM);
sigaddset(&act.sa_mask, SIGINT);
sigaddset(&act.sa_mask, SIGTERM);
sigaddset(&act.sa_mask, SIGTSTP);
sigaction(SIGALRM, &act, &oldact);
sigaction(SIGINT, &act, &oldact);
sigaction(SIGTERM, &act, &oldact);
sigaction(SIGTSTP, &act, &oldact);
act.sa_flags = 0;
Run Code Online (Sandbox Code Playgroud)

在此之后,我运行一个 for 循环来收集输入并将其打印出来(基本上就像 cat 一样)。

char *linebuf = NULL;
size_t n = 0;
int len;
while(1){
    len = getline(&linebuf, &n, stdin);
    if(len>0){
        printf("%s", linebuf);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,一旦我从处理的信号,返回getline()输入不再阻止,而是始终如一的回报-1,同时设置errnoEINTR这是一个中断的系统调用。我显然打算中断getline(),但如何重置它以便我可以继续读取输入?

有一些类似的问题并没有真正解决我的问题,但它可能会帮助您更好地理解问题。1 2

另一个有趣的花絮是我在signal()用于信号处理时没有遇到这个问题,但我改为,sigaction()因为它符合 POSIX。

小智 5

一个很晚的答案,但我会分享我最近在处理这个问题时学到的一些东西。当您在 sigaction 结构中将 sa_flags 设置为 0 时,您清除了获取信号时读取的默认行为。当您使用旧的 signal() 方法时,会保留此默认行为。要在您的情况下恢复此功能,您必须设置 sa_flags = SA_RESTART。但在这种情况下,信号处理程序将被调用,如果它不在读取中间,getline 将继续等待输入。如果信号发生在读取过程中,您仍然会得到 -1,并且您必须在恢复之前 clear() 流。但是,如果读取被阻塞等待数据并且信号发生,使用 SA_RESTART,您会在信号处理程序成功执行后立即返回读取。

我个人希望能够中断 getline(),这样我就可以很好地终止等待管道的程序,但遇到了麻烦,因为我使用了旧的 signal() 方法来设置我的处理程序。所以我会得到信号,但 getline 永远不会被中断,因为读取被阻塞等待数据,它只会在我的信号处理程序执行后自动重新启动读取。当我移动到 sigaction 结构并设置 sa_flags=0 时,它中断了 getline,导致它基本上返回 EINTR,我可以向我的进程发送一个信号来告诉它关闭。

我喜欢这个论坛。我无法计算它帮助解决了一个棘手的问题有多少次。以为我会回馈。希望这对下一个程序员有所帮助!