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

最佳答案

可能最简单的方法(尤其是如果您只有一个子进程)是捕获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$

09-06 20:46