来自 APUE :
防止应用程序必须处理中断的系统 通话中,4.2BSD引入了某些自动重启功能 中断的系统调用。 重新启动的是
ioctl
,read
,readv
,write
,writev
,wait
和waitpid
。如 我们已经提到过,这些功能的前五个被 仅当它们在较慢的设备上运行时才发出信号;wait
和waitpid
会在捕获到信号时始终被中断。 某些不希望重新启动操作的应用程序出现问题 如果被中断,则4.3BSD允许进程禁用此功能 按信号显示功能。
这是否意味着在引入自动重启之前,如果进程捕获到信号,wait
和waitpid
将立即停止等待并执行后续代码?>
例如:
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
void handler(int sig){}
void handler2(int sig){}
int main(){
pid_t pid;
int status;
signal(SIGUSR1, handler);
signal(SIGUSR2, handler2);
if((pid == fork()) < 0){
printf("fork error\n");
}else{
if(pid){
//child
//do something, needs several hours.
}else{
//parent
waitpid(pid, &status, 0);
printf("Hello world\n");
}
}
return 0;
}
如果不提供自动重启,则当我在后台gcc test.c && ./a.out &
中运行此程序时,我会发送信号kill -SIGUSR1 pid
或kill -SIGUSR2 pid
,{{1 }}将返回并执行waitpid
之后的代码。
如果提供自动重启,则waitpid(pid, &status, 0);
将再次执行,父级将保持等待状态。
我的理解正确吗?
答案 0 :(得分:1)
signal()
(System-V语义)的原始行为是:如果当前进程处于睡眠状态,则要中断任何系统调用,请执行信号处理程序,然后系统调用返回-EINTR
。然后,BSD4.3发明了 restart 机制,该机制将在中断后自动重新启动任何系统调用。如果涉及到信号处理程序,则可以避免为每个系统调用编写循环。
Linux并未更改signal()
syscall 的语义。但是,signal()
glibc包装函数现在默认情况下使用sigaction()
标志调用系统调用SA_RESTART
。因此,如果不需要需要重新启动行为,则必须调用sigaction()
并忽略该标志。
因此,您的代码确实在BSD和linux上都使用了 restart 机制。
答案 1 :(得分:0)
wait
和waitpid
像任何其他阻塞函数一样可以在errno
设置为EINTR
的情况下中断-这完全是因为 信号处理程序可以做的很少-主要是设置一些标志。现在,如果阻塞函数不返回EINTR
,您将如何以任何方式对信号做出反应?!
但这也意味着您需要对每个函数进行复杂的循环-您可能会有 some 信号,您知道它们不希望系统调用被中断,因此可以进行设置该信号会自动重启。