【问题标题】:Read and write using pipes使用管道读写
【发布时间】:2021-03-06 02:22:22
【问题描述】:

我有一个包含 2 个子进程的程序,它必须执行以下操作:

  • 使用父级从文件“data.txt”中读取数据并写入管道
  • 使用子级从管道中读取数据并过滤小写字母
  • 使用另一个孩子将过滤后的字母写到一个新文件中,每个字母都换行

我尝试过,它确实有效……有点。问题是,它将过滤后的字母写入所需的文件,但程序并没有停止。我做错了什么?

    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <signal.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/wait.h>
    #include <string.h>
    
    int parentChildpipeFileDescriptors[2], child1Child2FileDescriptors[2];
    
    void parentProcess()
    {
        close(child1Child2FileDescriptors[0]);
        close(child1Child2FileDescriptors[1]);
        close(parentChildpipeFileDescriptors[0]);
    
        int fileDescriptor = open("data.txt", O_RDONLY);
        char buffer[8];
        int store;
        while ((store = read(fileDescriptor, buffer, 8)))
        {
            write(parentChildpipeFileDescriptors[1], buffer, store);
        }
        close(fileDescriptor);
    
        close(parentChildpipeFileDescriptors[1]);
    }
    
    void child1Process()
    {
        close(parentChildpipeFileDescriptors[1]);
        close(child1Child2FileDescriptors[0]);
    
        char buffer[8];
        int store, count = 0;
        while ((store = read(parentChildpipeFileDescriptors[0], buffer, 8)))
        {
            for (int i = 0; i < store; i++)
            {
                if (buffer[i] >= 'a' && buffer[i] <= 'z')
                {
                    count++;
                    write(child1Child2FileDescriptors[1], &buffer[i], sizeof(buffer[i]));
                }
            }
        }
        printf("CHILD 1 FINISHED FILTERING\n");
    
        close(parentChildpipeFileDescriptors[0]);
        close(child1Child2FileDescriptors[1]);
    
        exit(count);
    }
    
    void child2Process()
    {
        close(parentChildpipeFileDescriptors[0]);
        close(child1Child2FileDescriptors[1]);
    
        mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
        char *fileName = "stat.txt";
        int newFileDescriptor = creat(fileName, mode);
        char buffer;
        int store;
        while ((store = read(child1Child2FileDescriptors[0], &buffer, 1)))
        {
            write(newFileDescriptor, &buffer, sizeof(buffer));
            write(newFileDescriptor, "\n", 1);
        }
        close(newFileDescriptor);
    
        printf("CHILD 2 FINISHED WRITING'\n");
    
        close(child1Child2FileDescriptors[0]);
        close(parentChildpipeFileDescriptors[1]);
    
        exit(444);
    }
    
    int main(int argc, char const *argv[])
    {
        if (pipe(parentChildpipeFileDescriptors) < 0)
        {
            printf("ERROR CREATING PIPE\n");
            exit(-100);
        }
    
        if (pipe(child1Child2FileDescriptors) < 0)
        {
            printf("ERROR CREATING PIPE\n");
            exit(-101);
        }
    
        pid_t child1PID = fork();
        if (child1PID < 0)
        {
            printf("ERROR CREATING CHILD\n");
            exit(-200);
        }
        if (!child1PID)
        {
            child1Process();
        }
    
        pid_t child2PID = fork();
        if (child2PID < 0)
        {
            printf("ERROR CREATING CHILD\n");
            exit(-201);
        }
        if (!child2PID)
        {
            child2Process();
        }
    
        parentProcess();
        int status1, status2;
        waitpid(child1PID, &status1, 0);
        waitpid(child2PID, &status2, 0);
        printf("CHILD 1 TERMINATED WITH EXIT STATUS: %d\n", WEXITSTATUS(status1));
        printf("CHILD 2 TERMINATED WITH EXIT STATUS: %d\n", WEXITSTATUS(status2));
    
        return 0;
    }

【问题讨论】:

    标签: c process pipe parent-child write


    【解决方案1】:

    child1process 中的读取循环永远不会终止,因为 child2 仍然打开了该管道的写入端。你需要执行:

    close(parentChildpipeFileDescriptors[1]);
    

    在进入读取循环之前。一般规则是,如果一个进程不打算使用文件描述符,它应该立即关闭它。

    【讨论】:

    • 我认为这是问题所在。即使我没有使用它,我也打开了该管道的书写部分。
    【解决方案2】:

    你的 while ((store = read(parentChildpipeFileDescriptors[0], buffer, 8))) 循环永远不会结束。

    父母需要告诉孩子没有更多的数据来了,它不会再读了。 你可以通过发送一个特殊的字节来做到这一点。

    例子:

    在父级中:

    char endByte = 0x1;
    write(parentChildpipeFileDescriptors[1], &endByte, 1);
    //then close
    

    在孩子的while循环中:

    if(buffer[i] ==  0x1){
        printf("CHILD 1 FINISHED FILTERING\n");
        fflush(stdout);
        close(parentChildpipeFileDescriptors[0]);
        close(child1Child2FileDescriptors[1]);
    
        exit(count);
    };
    

    【讨论】:

    • 你不需要写一个特殊的字节。关闭文件描述符就足够了。如果孩子在下一次读取时没有得到 EOF,那是因为其他进程仍然打开了管道的写入端。
    • 这行得通,但正如@WilliamPursell 所说,我认为这不是正确的做法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多