“等待和waitpid总是在捕获到信号时中断”是什么意思?

时间:2019-03-29 07:23:54

标签: c unix signals wait interrupt

来自 APUE

  

防止应用程序必须处理中断的系统   通话中,4.2BSD引入了某些自动重启功能   中断的系统调用。   重新启动的是ioctlreadreadvwritewritevwaitwaitpid。如   我们已经提到过,这些功能的前五个被   仅当它们在较慢的设备上运行时才发出信号; waitwaitpid   会在捕获到信号时始终被中断。   某些不希望重新启动操作的应用程序出现问题   如果被中断,则4.3BSD允许进程禁用此功能   按信号显示功能。

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

例如:

#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 pidkill -SIGUSR2 pid,{{1 }}将返回并执行waitpid之后的代码。

如果提供自动重启,则waitpid(pid, &status, 0);将再次执行,父级将保持等待状态。

我的理解正确吗?

2 个答案:

答案 0 :(得分:1)

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

Linux并未更改signal() syscall 的语义。但是,signal() glibc包装函数现在默认情况下使用sigaction()标志调用系统调用SA_RESTART。因此,如果不需要需要重新启动行为,则必须调用sigaction()并忽略该标志。

因此,您的代码确实在BSD和linux上都使用了 restart 机制。

答案 1 :(得分:0)

waitwaitpid像任何其他阻塞函数一样可以在errno设置为EINTR的情况下中断-这完全是因为 信号处理程序可以做的很少-主要是设置一些标志。现在,如果阻塞函数返回EINTR,您将如何以任何方式对信号做出反应?!

但这也意味着您需要对每个函数进行复杂的循环-您可能会有 some 信号,您知道它们不希望系统调用被中断,因此可以进行设置该信号会自动重启。