C检测子程序流程中的错误

时间:2019-06-08 06:01:07

标签: c popen

我正在使用popen来读取第三方程序的输出。如果子程序失败,我想检测并重新启动。

我该怎么做?如果孩子死亡,则该过程不会正常退出,因此无法使用WEXITSTATUS进行检查。

还有其他方法吗?

这是一个简单的例子:

PINGER.C

#include <string.h>
#include <stdio.h>
#include <unistd.h>

int
main(int argc, char **argv)
{
    int i = 0;
    while (1)
    {
        //fprintf(stderr, "StdErr %d\n", i);
        printf("stdout %d\n", i++);
        fflush(stdout);

        if (i == 5)
            i = i / 0; // Die a horrible death

        sleep(1);
    }
}

WATCHER.C

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>

int
main(int argc, char **argv)
{
    char *cmd = "./pinger";
    printf("Running '%s'\n", cmd);

    FILE *fp = popen(cmd, "r");
    if (!fp)
    {
        perror("popen failed:");
        exit(1);
    }

    char inLine[1024];
    int  bytesRead = 0;
    int  i = 0;

    while (fgets(inLine, sizeof(inLine), fp) != NULL)
    {
        int len = strlen(inLine);
        if (inLine[len-1] == '\n')
            inLine[len-1] = '\0';

        printf("Received: '%s'\n", inLine);
    }

    printf("feof=%d ferror=%d: %s\n", feof(fp), ferror(fp), strerror(errno));

    int rc = pclose(fp);
    printf("pclose returned: %d. IFEXITED=%d\n", rc, WIFEXITED(rc));
}

以下是输出:

$ ./popenTest
calling popen
Running './pinger'
pipe open
Received: 'stdout 0'
Received: 'stdout 1'
Received: 'stdout 2'
Received: 'stdout 3'
Received: 'stdout 4'
feof=1 ferror=0: Success
pclose returned: 8. IFEXITED=0 EXITSTATUS=0

({According to this post,如果命令没有正常退出,您实际上不能使用WEXITSTATUS,但我还是尝试过

2 个答案:

答案 0 :(得分:0)

一个进程通过从其main()返回退出代码或调用_exit(statuscode)来返回退出状态。如果该过程异常终止(例如,由于信号或故障),则该过程将永远没有机会进行任何此类操作,因此不会有退出状态。

在这种情况下,您所能知道的是该过程因错误而终止。

如果要在程序因错误终止的所有情况下重新启动,则需要同时检查WIFEXITED和WEXITSTATUS:

do {
    rc = run_your_child_process();

} while (!WIFEXITED(rc) || WEXITSTATUS(rc) == 0);

// child terminated without error

答案 1 :(得分:0)

阅读pclose()(和popen()的POSIX规范)。它说:

  

返回值

     

成功返回后,pclose()将返回命令语言解释器的终止状态。否则,pclose()将返回-1并设置errno来指示错误。

因此,您可以通过pclose()的返回值间接获取进程的退出状态。那将是一个介于0到255之间的数字。Shell经常通过返回值128 + signal_number来报告“信号死亡的孩子”。该规范概述了状态可能不可用的情况(例如,您的程序名为wait(),并在您调用popen()之前获得了pclose()打开的进程的信息)。阅读popen()的规范说明了pclose()的规范中“命令语言解释器”的使用。