3

在我的 C++ 应用程序中,我看到一个 pclose() 挂起,因为管道的进程挂起并且从未退出。无论如何我可以做类似 select() 的事情来测试 pclose() 是否会因为子进程已经完成而返回?如果可能的话,我宁愿不做 fork() 而不是 popen() 。如果 fork() 是唯一的解决方案,是否有使用 fork() 替换 popen() / pclose() 场景的示例?

4

1 回答 1

1

可能最简单的方法,特别是如果您只有一个子进程,是捕获SIGCHLD并设置一个进程已终止并且pclose()可以调用的标志。

这是一个简单的例子:

sillyprog.c

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

int main(void)
{
    printf("This is some data from the child.\n");
    fflush(stdout);
    sleep(5);
    return 0;
}

pc.c

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

volatile sig_atomic_t child_done = 0;

void handler(int signum)
{
    if ( signum == SIGCHLD ) {
        child_done = 1;
    }
}

int main(void)
{
    /*  Set signal handler  */

    struct sigaction sa;
    sa.sa_handler = handler;
    sa.sa_flags = 0;
    sigemptyset(&sa.sa_mask);
    if ( sigaction(SIGCHLD, &sa, NULL) == -1 ) {
        perror("couldn't set signal handler");
        return EXIT_FAILURE;
    }

    /*  Open pipe  */

    FILE * fp = popen("./sillyprog", "r");
    if ( !fp ) {
        fprintf(stderr, "Couldn't open pipe\n");
        return EXIT_FAILURE;
    }

    /*  Get a line from pipe  */

    char buffer[100];
    if ( !fgets(buffer, 100, fp) ) {
        fprintf(stderr, "Error calling fgets()\n");
        return EXIT_FAILURE;
    }

    const size_t len = strlen(buffer);
    if ( len && buffer[len - 1] == '\n' ) {
        buffer[len - 1] = 0;
    }
    printf("Got '%s' from pipe.\n", buffer);

    /*  Wait for child to finish  */

    while ( !child_done ) {
        printf("Child not ready, waiting...\n");
        sleep(1);
    }

    /*  Close pipe  */

    if ( pclose(fp) == -1 ) {
        fprintf(stderr, "Error calling pclose()\n");
        return EXIT_FAILURE;
    }
    else {
        printf("pclose() successfully called.\n");
    }

    return 0;
}

输出:

paul@horus:~/src/sandbox$ ./pc
Got 'This is some data from the child.' from pipe.
Child not ready, waiting...
Child not ready, waiting...
Child not ready, waiting...
Child not ready, waiting...
Child not ready, waiting...
pclose() successfully called.
paul@horus:~/src/sandbox$ 
于 2014-12-19T23:51:15.310 回答