“当捕获到信号时,wait 和 waitpid 总是被中断”是什么意思?

Ric*_*ick 4 c unix signals interrupt wait

来自APUE

\n\n
\n

为了防止应用程序必须处理中断的系统调用,4.2BSD 引入了自动重新启动某些中断的系统调用。自动重新启动的系统调用有ioctlreadreadvwritewritevwaitwaitpid。正如我们\xe2\x80\x99提到的,这些函数中的前五个只有在运行速度较慢的设备上时才会被信号中断;当捕获到信号时, \nwait和\n 总是被中断。waitpid由于这会给某些应用程序带来问题,如果操作被中断,这些应用程序不希望重新启动操作,因此 4.3BSD 允许进程在每个信号的基础上禁用此功能。

\n
\n\n

这是否意味着在引入自动重启之前,如果进程捕获到信号,waitwaitpid立即停止等待并执行后续代码?

\n\n

例如:

\n\n
#include <unistd.h>\n#include <sys/types.h>\n#include <signal.h>\n\nvoid handler(int sig){}\nvoid handler2(int sig){}\n\n\nint main(){\n    pid_t pid;\n    int status;\n    signal(SIGUSR1, handler);\n    signal(SIGUSR2, handler2);    \n\n    if((pid == fork()) < 0){\n        printf("fork error\\n");\n    }else{\n        if(pid){\n            //child\n            //do something, needs several hours.\n        }else{\n            //parent\n            waitpid(pid, &status, 0);\n            printf("Hello world\\n");\n        }\n    }\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果不提供自动重启,当我在后台运行这个程序时gcc test.c && ./a.out &,我发送一个信号kill -SIGUSR1 pidkill -SIGUSR2 pid,将返回并执行waitpid后面的代码。waitpid(pid, &status, 0);

\n\n

如果提供自动重启waitpid将再次执行并且父级将保持等待。

\n\n

我的理解正确吗?

\n

Ctx*_*Ctx 5

(System-V 语义)的原始行为signal()是,如果进程当前处于睡眠状态,则中断任何系统调用,执行信号处理程序,系统调用以-EINTR. 然后,BSD4.3发明了重启机制,任何系统调用被中断后都会自动重启。如果涉及信号处理程序,这可以避免为每个系统调用编写循环。

signal() Linux 没有改变syscall的语义。然而,现在signal() glibc 包装函数默认调用sigaction()带标志的系统调用。SA_RESTART因此,如果您不需要重新启动行为,则必须调用sigaction()并忽略该标志。

所以,你的代码确实在 BSD 和 linux 上都利用了重启机制