我编写了一个非常小的测试程序,以在errno
被处理的信号中断时检查read()
的值。
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
void handler(int sig){
printf("signal: %d\n", sig);
}
int main(){
signal(SIGINT, handler);
char arr[10];
read(0, arr, 10);
perror("emsg");
return 0;
}
根据我所知道的一切以及read(2)
上的手册页,
EINTR The call was interrupted by a signal before any data was read;
see signal(7).
read
应该返回-1
并将errno
设置为EINTR
。但是,程序的输出表明从信号处理程序返回后,它在read
上再次阻塞。
这对我来说绝对没有意义,我无法弄清楚出了什么问题。
这是我得到的输出:
$ ./a.out
^Csignal: 2
^Csignal: 2
^Csignal: 2
^Csignal: 2
hello
emsg: Success
我的问题与this one不同。后者在任何地方都没有提到系统调用中断时会发生什么。该讨论的关键是应使用的内容。
在同一线程上另外this answer说signal()
在下面调用sigaction()
,那么为什么在系统调用的情况下两者的行为不同?
答案 0 :(得分:2)
根据我所知道的一切和
read(2)
上的手册页,EINTR The call was interrupted by a signal before any data was read; see signal(7).
read
应该返回-1
并将errno
设置为EINTR
。
您对此读得太多了。 read()
可以返回-1并将errno
设置为EINTR
,该组合应解释为表示已被信号中断(在读取任何数据之前) )。甚至可以肯定地说,如果read
由于被信号中断而失败,那么这就是期望它出现的方式。但这并不意味着read
可以保证在阻塞时收到信号也会失败。
但是,程序的输出表明它再次在 从信号处理程序返回后读取。
这确实是一种可能的行为。特别是,它是signal()
和信号处理的BSD语义的一部分,并且是Glibc的默认设置(受_BSD_SOURCE
功能测试宏的约束),因此,这就是您期望的默认设置在Mac(由于BSD)和大多数Linux(由于Glibc)上。 the manual page for Glibc's implementation of signal()
的“可移植性”部分对此问题进行了详细介绍。
此外,在同一线程上的此答案还表明
signal()
调用sigaction()
在下面,为什么在系统情况下该行为 两者的呼叫方式有所不同?
sigaction()
的关键在于,它提供了用于指定处理已设置其信号的信号的所有细节的机制,尤其是
因此,如果signal()
的某些实现通过调用sigaction()
进行操作,则在随后接收到信号时,这些或其他辅助行为没有固有的含义。这也不意味着直接通过sigaction()
注册该信号的处理程序必须产生与通过signal()
间接进行该操作相同的效果-这都取决于sigaction()
的参数。呼叫者可以选择。
特别注意上面链接的联机帮助页中的建议:
signal()
的唯一可移植用法是设置信号的处理方式 到SIG_DFL
或SIG_IGN
。何时的语义 使用signal()
来建立一个信号处理程序,该信号处理程序在整个系统中有所不同(POSIX.1明确允许这种变化); 请勿为此目的使用。
(强调原文)
假设您希望系统调用 not 在被SIGINT
中断并由您的处理程序处理后恢复,您可以通过避免指定{{1 }}。最有可能的是,您也不需要任何其他标志,所以这意味着(例如)这样的东西:
sigaction