我想使用alarm()
来设置recvfrom
的超时时间。但是发现当使用signal()
注册SIGALRM
的处理程序时,已经捕获了SIGALRM
,然后调用了信号处理程序。但是从处理程序返回后,recvfrom()
仍然阻塞,而没有数据到来,并且没有EINTR
错误。为什么? signal()
是否自动设置SA_RESTART
标志?
这是代码:
signal(SIGALRM, sig_handler);
while(1)
{
alarm(5);
n = recvfrom(sock, buf, BUF_MAX, 0, (struct sockaddr*)&addr, &len);
if(n < 0)
{
if(errno == EINTR)
{
printf("recvfrom timeout\n");
continue;
}
else
{
printf("recvfrom error\n");
}
}
else
{
printf("data: %s\n", buf);
alarm(0);
}
}
void sig_handler(int signo)
{
return;
}
答案 0 :(得分:1)
根据signal
的手册页,
是否重新启动阻止调用是依赖于平台的属性:
Linux的情况如下:
- 内核的signal()系统调用提供了System V语义。
- 默认情况下,在glibc 2及更高版本中,signal()包装函数不会调用内核系统调用。相反,它使用提供BSD的标志调用sigaction(2) 语义。只要定义了合适的功能测试宏,就会提供此默认行为:glibc 2.19及更早版本的_BSD_SOURCE或_DEFAULT_SOURCE glibc 2.19及更高版本。 (默认情况下,定义了这些宏;有关详细信息,请参阅feature_test_macros(7)。)如果未定义此类功能测试宏,则signal() 提供System V语义。
由于BSD语义等同于使用以下标志调用sigaction(2)
:
sa.sa_flags = SA_RESTART;
和System V语义没有SA_RESTART
,你看到的是你的程序正在以BSD方式运行,因此你应该确保使用所述的功能测试宏来获得程序的定义行为。