首页 > 解决方案 > 如果孩子没有状态变化,如何取消waitpid?

问题描述

免责声明:C 中的绝对新手,我以前主要使用 Java。

在许多 C 初学者教程中,waitpid在进程管理示例中使用它来等待其子进程完成(或使用类似的选项进行状态更改WUNTRACED)。但是,如果没有发生此类状态更改,无论是通过直接用户输入还是编程(例如超时),我都找不到有关如何继续的任何信息。那么有什么好的撤消方法waitpid呢?类似于SIGCONT停止的进程,而是延迟的进程waitpid

或者,如果这个想法没有意义,知道为什么会很有趣。

标签: cwaitpid

解决方案


如果我建议使用alarm()呢?在倒计时结束后alarm()交付(有关更多详细信息,请参见手册页)。但是从手册页来看,默认处置是终止进程。因此,您需要注册一个信号处理程序来处理. 代码如下...SIGALRMalarm() signalsSIGALRMSIGALRM

#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void sigalrm(int signo)
{
    return; // Do nothing !
}

int main()
{
    struct sigaction act, oldact;

    act.sa_handler = sigalrm;   // Set the signal handler
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;

#ifdef SA_INTERRUPT // If interrupt defined set it to prevent the auto restart of sys-call
    act.sa_flags |= SA_INTERRUPT;
#endif

    sigaction(SIGALRM, &act, &oldact);

    pid_t fk_return = fork();
    if (fk_return == 0) {   // Child never returns
        for( ; ; );
    }

    unsigned int wait_sec = 5;
    alarm(wait_sec);    // Request for SIGALRM

    time_t start = time(NULL);
    waitpid(-1, NULL, 0);
    int tmp_errno = errno;  // save the errno state, it may be modified in between function calls.
    time_t end = time(NULL);

    alarm(0);  // Clear a pending alarm
    sigaction(SIGALRM, &oldact, NULL);

    if (tmp_errno == EINTR) {
        printf("Child Timeout, waited for %d sec\n", end - start);
        kill(fk_return, SIGINT);
        exit(1);
    }
    else if (tmp_errno != 0)    // Some other fatal error
        exit(1);

    /* Proceed further */

    return 0;
}

输出

Child Timeout, waited for 5 sec

注意:您不必担心,SIGCHLD因为它的默认处置是忽略。

编辑

为了完整起见,保证SIGALRM不会交付给孩子。这是来自的手册页alarm()

由 alarm() 创建的警报在 execve(2) 中保留,不会被通过 fork(2) 创建的子级继承。

编辑 2

我不知道为什么一开始它没有打动我。一种简单的方法是阻止SIGCHLD并调用sigtimedwait()支持超时选项的方法。代码是这样的......

#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main()
{
    sigset_t sigmask;
    sigemptyset(&sigmask);
    sigaddset(&sigmask, SIGCHLD);
    sigprocmask(SIG_BLOCK, &sigmask, NULL);

    pid_t fk_return = fork();
    if (fk_return == 0) {   // Child never returns
        for( ; ; );
    }

    if (sigtimedwait(&sigmask, NULL, &((struct timespec){5, 0})) < 0) {
        if (errno == EAGAIN) {
            printf("Timeout\n");
            kill(fk_return, SIGINT);
            exit(1);
        }
    }

    waitpid(fk_return, NULL, 0);    // Child should have terminated by now.

    /* Proceed further */

    return 0;
}

输出

Timeout

推荐阅读