简体   繁体   English

C叉管多道工序

[英]C fork and pipe multiple process

I'm trying to implement this command cat /etc/passwd | grep 1000 | cut -d: -f1 我正在尝试实现此命令cat /etc/passwd | grep 1000 | cut -d: -f1 cat /etc/passwd | grep 1000 | cut -d: -f1 cat /etc/passwd | grep 1000 | cut -d: -f1 in C using system calls fork and pipe. 在C中使用系统调用fork和pipe cat /etc/passwd | grep 1000 | cut -d: -f1
When I use only two commands cmd1 | cmd2 当我仅使用两个命令cmd1 | cmd2 cmd1 | cmd2 so 1 fork it works fine but when I'm using more than 2 process the problem occurs cmd1 | cmd2所以1个fork可以正常工作,但是当我使用2个以上的进程时,会出现问题
Here is my code, I think the problem is in the grand parent block 这是我的代码,我认为问题出在Grand Parent块中

Update : 更新
I closed some unclosed file descriptors 我关闭了一些未关闭的文件描述符

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


int main(){
    int fd[2], fd2[2];
    pid_t pid, pid2;
    char str[100];

    if(pipe(fd) != 0){
        fprintf(stderr, "Error pipe.\n");
        return 1;
    }
    if(pipe(fd2) != 0){
        fprintf(stderr, "Error pipe.\n");
        return 1;
    }

    do{
        pid = fork();
    }while(pid == -1 && errno == EAGAIN);

    if(pid == -1){
        perror("fork()");
        exit(1);
    }

    if(pid == 0){
        pid2 = fork();
        if(pid2 == 0){
            // fprintf(stderr, "1 - Grand Child\n");
            close(fd[0]);
            dup2(fd[1], 1);
            close(fd[1]);
            execlp("cat", "cat", "/etc/passwd", NULL);
            perror("cat error");
        }else{
            wait(&pid2);
            // fprintf(stderr, "2 - Child\n");
            close(fd[1]);
            dup2(fd[0], 0);
            close(fd[0]);

            up2(fd2[1], 1);
            close(fd2[1]);

            execlp("grep", "grep", "1000", NULL);
            perror("grep failed");
        }
        return 1;
    }else{
        wait(&pid);
        // fprintf(stderr, "3 - Parent\n");
        close(fd[0]);
        dup2(fd2[0], 0);
        close(fd2[0]);
        execlp("cut", "cut", "-d:", "-f1", NULL);
        perror("cut failed");
        return 1;
    }
    return 0;
}

You need to close all unused file descriptors in both children and parents! 您需要关闭孩子和父母中所有未使用的文件描述符! In this case, when using dup2(), all file descriptors associated with pipes may be closed. 在这种情况下,使用dup2()时,可能会关闭与管道关联的所有文件描述符。

For clarity I used macros for file descriptors associated with stdin and stdout. 为了清楚起见,我将宏用于与stdin和stdout相关的文件描述符。 Macros STDIN_FILENO and STDOUT_FILENO are declared in unistd.h. 宏STDIN_FILENO和STDOUT_FILENO在unistd.h中声明。

Waiting for children ( wait(&pid); and wait(&pid2); ) is not needed. 不需要等待孩子( wait(&pid);wait(&pid2); )。 You do not need to wait for cat to end before running grep , as grep will process them as they come. 您无需等待cat结束即可运行grep ,因为grep会在它们出现时对其进行处理。 Pipe should have a big buffer, like 65536 bytes, so after cat command ends data will be buffered in pipe, but it is not something to count on. 管道应具有较大的缓冲区,如65536字节,因此在cat命令结束后,数据将在管道中进行缓冲,但这并不是值得依靠的。

The following code, with only minor changes, works: 以下代码仅需进行少量更改即可起作用:

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

int main(){
    int fd[2], fd2[2];
    pid_t pid, pid2;
    char str[100];

    if(pipe(fd) != 0){
        fprintf(stderr, "Error pipe.\n");
        return 1;
    }
    if(pipe(fd2) != 0){
        fprintf(stderr, "Error pipe.\n");
        return 1;
    }

    do{
        pid = fork();
    }while(pid == -1 && errno == EAGAIN);

    if(pid == -1){
        perror("fork()");
        exit(1);
    }

    if(pid == 0){
        pid2 = fork();
        if(pid2 == 0){
            // fprintf(stderr, "1 - Grand Child\n");
            dup2(fd[1], STDOUT_FILENO); // 1);
            close(fd[0]);
            close(fd[1]);
            close(fd2[1]);
            close(fd2[0]);

            execlp("cat", "cat", "/etc/passwd", NULL);
            perror("cat error");
        }else{
            // wait(&pid2);
            // fprintf(stderr, "2 - Child\n");
            dup2(fd[0], STDIN_FILENO); //0);
            dup2(fd2[1], STDOUT_FILENO); // 1);
            close(fd[0]);
            close(fd[1]);
            close(fd2[1]);
            close(fd2[0]);

            execlp("grep", "grep", "1000", NULL);
            perror("grep failed");
        }
        return 1;
    }else{
        // wait(&pid);
        // fprintf(stderr, "3 - Parent\n");
        dup2(fd2[0], STDIN_FILENO); //0);
        close(fd[0]);
        close(fd[1]);
        close(fd2[1]);
        close(fd2[0]);

        execlp("cut", "cut", "-d:", "-f1", NULL);
        perror("cut failed");
        return 1;
    }
    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM