C 应用程序在将数据写入管道后挂起。如何检查 "cat" 进程是否完成?

C application hangs after writing data to a pipe. How to check if "cat" process is done?

我的 C 应用程序我想将数据写入管道进程。接下来,我想要一个文件描述符,其中缓冲了所有写入的数据。为此,我选择使用 cat 命令。以下是我的代码(问题的简化版,即):

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

#define PIPE_READ 0
#define PIPE_WRITE 1

/*
 * 
 */
int main(int argc, char** argv) {
    int fd[2];
    int childpid;
    int writePntr;
    pipe(fd);
    if ((childpid = fork()) == -1) {
        perror("fork");
    }
    if (childpid == 0) {
        dup2(fd[PIPE_WRITE], STDOUT_FILENO); // send stdout to the pipe
        char a = 'a';
        write(fd[PIPE_WRITE], &a, 1);
        char b = 'b';
        write(fd[PIPE_WRITE], &b, 1);
        write(fd[PIPE_WRITE], '[=11=]', 1);
        close(fd[PIPE_WRITE]);
        close(fd[PIPE_READ]);
        char *cmd = "cat";
        char *argv[2];
        argv[0] = "cat";
        argv[1] = NULL;

        execvp(cmd, argv);
        exit(1);
    } else {
        close(fd[PIPE_WRITE]);
        writePntr = fd[PIPE_READ];
    }
    wait(NULL);
    char readbuffer[1];
    while (read(writePntr, readbuffer, 1) > 0) {
        printf(readbuffer);
    }
    close(writePntr);

    return (EXIT_SUCCESS);
}

此代码的问题在于它挂在 wait(&childpid);while (read(writePntr, readbuffer, 1) > 0) { 上(如果我删除等待语句)。从字面上看,它似乎在 while 循环中永远循环,这意味着该过程由于某种原因永远不会结束。

在这个过于简化的代码版本中,我将字符 'a' 和 'b' 写入管道,后跟 NULL 终止符(尽管我不确定是否需要这样做)。我相信我关闭了管道的所有必要侧面。在代码的真实版本中,'a' 和 'b' 实际上是写入管道的完整缓冲区。我必须这样做的原因是,我想要一个文件描述符,它包含附加到另一个文件描述符的所有数据的另一个文件描述符的所有数据。

有谁知道附加代码挂起的原因吗?

查看 wait(2) 的手册页 -- 它可能没有按照您认为的方式执行,即等待您创建的子进程终止。

此外,该参数是写入已终止进程状态的位置,而不是您正在等待的进程的 PID -- 那将是 waitpid,这是相关的。

请注意,您正在为子项和父项调用 wait - 因此子项正在等待其子项在死亡前死亡,并通知其父项。

这是代码,我试着在评论中解释。

int main(int argc, char** argv) {
        int fd[2];
        int childpid;
        int writePntr;
        pipe(fd);
        if ((childpid = fork()) == -1) {
                perror("fork");
        }
        if (childpid == 0) {
                dup2(fd[PIPE_WRITE], STDOUT_FILENO); // send stdout to the pipe
                char a = 'a';
                write(fd[PIPE_WRITE], &a, 1);
                char b = 'b';
                write(fd[PIPE_WRITE], &b, 1);
                write(fd[PIPE_WRITE], '[=10=]', 1);
                dup2(3,0);
                dup2(4,1); /* you must duplicate pipe[1] to stdout */
                char *cmd = "/bin/cat";
                char *argv[2];
                argv[0] = "cat";
                argv[1] = "data";/* data is the file name */
                execlp(cmd, argv[0],argv[1],NULL);
                perror("execvp");

                exit(1);
        } else {
                close(fd[PIPE_WRITE]);
                writePntr = fd[PIPE_READ];
        }
        wait(NULL);
        char readbuffer; /* take only char */
        while (read(writePntr, &readbuffer, 1) > 0) {/* read char by char */
                printf("%c \n",readbuffer);
        }
        close(writePntr);
        return (EXIT_SUCCESS);
}