我有一个使用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;
在此之后,我运行一个for循环来收集输入并将其打印出来(基本上就像猫一样)。
char *linebuf = NULL;
size_t n = 0;
int len;
while(1){
len = getline(&linebuf, &n, stdin);
if(len>0){
printf("%s", linebuf);
}
}
但是,一旦我从处理信号返回,getline()
不再阻止输入,而是在-1
设置为errno
时始终返回EINTR
系统调用。我显然打算打断getline()
,但是如何重置它以便我可以继续读取输入?
有一些类似的问题并没有真正解决我的问题,但它可能会帮助您更好地理解问题。 1 2
另一个有趣的消息是,当我使用signal()
进行信号处理时,我没有遇到此问题,但我更改为sigaction()
,因为它符合POSIX标准。
答案 0 :(得分:4)
您链接的其中一个问题实际上有您的答案。但首先,有几个参考文献。请注意,getline
在内部使用其他功能(可能是read
)。
来自read
的手册页:
如果read()在读取任何数据之前被信号中断,它将返回-1并将errno设置为[EINTR]。
...
...还有一个附加函数select(),其目的是暂停,直到在指定的文件描述符上检测到指定的活动(要读取的数据,要写入的空间等)。在为那些系统编写的应用程序中,通常在read()之前使用的应用程序(例如键盘输入)中使用,因为需要中断I / O.
来自select
的手册页:
pselect()函数应检查文件描述符集...以查看它们的某些描述符是否已准备好进行读取,是否已准备好写入,或者是否有待处理的异常条件。
因此,您可以使用select
来了解何时开始阅读是安全的。但是,这仍然不会阻止read
稍后中断。 (我刚才这样说是为了你的信息)。
要实际清除流的错误标记,将this answer作为一个链接的问题状态(尽管在C ++中),您需要使用clearerr
函数清除任何错误标记。流。请注意,手册页(以及C标准)没有具体说明它也清除了“中断”标志,但这仅仅是因为它超出了C的范围,并且属于POSIX领域。
作为旁注,我想说,请不要使用memset
来清除结构。 C有一个非常好的方法:
struct sigaction act = {0};
或者如果你想要迂腐,因为struct sigaction
的第一个元素可能是另一个结构或数组,你可以分配给它的一个强制字段:
struct sigaction act = { .sa_handler = NULL };
答案 1 :(得分:4)
答案非常晚,但我会分享一些我最近学到的东西。在sigaction结构中将sa_flags设置为0时,在获取信号时清除了读取的默认行为。使用旧的signal()方法时,将保留此默认行为。要在您的情况下恢复,您必须设置sa_flags = SA_RESTART。但是在这种情况下,将调用信号处理程序,如果getline不在读取的中间,则getline将继续等待输入。如果信号发生在读取过程中,您仍然会得到-1,并且您必须在恢复之前清除()流。但是如果读取被阻塞等待数据并且信号发生,则使用SA_RESTART,您会在信号处理程序成功执行后立即返回读取。
我个人希望能够中断getline()所以我可以很好地终止一个等待管道的程序并且遇到麻烦,因为我使用旧的signal()方法来设置我的处理程序。所以我会得到信号,但getline永远不会被中断,因为读取被阻止等待数据,它只会在我的信号处理程序执行后自动重新启动读取。当我移动到sigaction结构并设置sa_flags = 0时,它中断了getline,导致它基本上返回EINTR,我可以向我的进程发送一个信号告诉它关闭。
我喜欢这个论坛。我无法计算它帮助解决棘手问题的次数。以为我会回馈。希望这有助于下一个程序员!