管道排序并返回主要

时间:2017-01-13 10:58:30

标签: c unix pipe fork

所以我试图理解管道在UNIX中是如何工作的,我试图将文本管道排序,对它们进行排序并将它们管道传回main to doo。但是当执行到达时:

注意:程序将文本文件作为参数。

execlp("sort", "sort",(char *)0);

程序停止并保持静止,就像从管道中等待一样。我知道我必须了解UNIX管道。

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

int main (int argc, char **argv){
    int pipe1[2];
    int pipe2[2];

    pid_t childpid;

    FILE *fdin;

    long fsize;

    pipe(pipe1);
    pipe(pipe2);

// error handling
    if ((childpid = fork()) == -1){
        perror("fork");
        exit(1);
    }

// parent load file, write to pipe1
    if (childpid != 0){
        char buf[1024];
        close(pipe1[0]);
        close(pipe2[1]);

        fdin = fopen(argv[1], "r");

        //fseek(fdin, 0, SEEK_END);
        //fsize = ftell(fdin);
        //fseek(fdin, 0, SEEK_SET);

        fread(buf, sizeof(buf), 1, fdin);
        fclose(fdin);

        dup2(pipe1[1],STDOUT_FILENO);
        write(pipe1[1], buf, sizeof(buf));
        close(pipe1[1]);
    }
    else if (childpid == 0){
        char buf[1024];
        close(pipe1[1]);
        close(pipe2[0]);
        //dup2(pipe2[1], STDOUT_FILENO);
        //dup2(pipe1[0], STDIN_FILENO);

        read(pipe1[0], buf, sizeof(buf));
        close(pipe1[0]);

        printf("%s\n\n", buf);

        dup2(pipe2[1], STDOUT_FILENO);
        close(pipe2[1]);

        execlp("sort", "sort",(char *)0);

        printf("%s\n", buf);
        exit(0);
    }

// wait child
    wait(NULL);

// parent read pipe 2 and print
    if (childpid != 0){
        // DOOOO
        //read(pipe2[0], buf, 1024);
        //printf("%s\n", buf);
    }
    return 0;
}

死锁 Thought Picture 1 Dead Lock

更新 Thought Picture 2

更新:1

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

//char *message = "This is a message!!!";

int main (int argc, char **argv){
    int pipe1[2];
    int pipe2[2];

    pid_t childpid[2];

    FILE *fdin;
    char buf[1024];

    //long fsize;

    pipe(pipe1);
    pipe(pipe2);

// error handling
    if ((childpid[0] = fork()) == -1)
    {
        perror("fork");
        exit(1);
    }

    // parent load file, write to pipe1
    if (childpid[0] != 0){

        close(pipe1[0]);
        close(pipe2[1]);


        fdin = fopen(argv[1], "r");

        //fseek(fdin, 0, SEEK_END);
        //fsize = ftell(fdin);
        //fseek(fdin, 0, SEEK_SET);

        fread(buf, sizeof(buf), 1, fdin);
        fclose(fdin);

        dup2(pipe1[1],STDOUT_FILENO);
        write(pipe1[1], buf, sizeof(buf));
        close(pipe1[1]);
    }
    else if (childpid[0] == 0){
        buf[0] = '\0';
        int pipe3[2];

        pipe(pipe3);

        close(pipe1[1]);
        close(pipe2[0]);

        //dup2(pipe2[1], STDOUT_FILENO);
        dup2(pipe1[0], STDIN_FILENO);
        //dup2(pipe3[1],STDOUT_FILENO);

        read(pipe1[0], buf, sizeof(buf));
        close(pipe1[0]);

        write(pipe3[1], buf, sizeof(buf));
        printf("-PIPED BUFF-\n%s\n\n", buf);

        if ((childpid[1] = fork()) == -1){
            perror("fork second child");
            exit(1);
        }
        // Child of child (sort call)
        if (childpid[1] != 0){
            close(pipe2[1]);
            close(pipe3[0]);
            printf("I AM YOUR FATHER LOOK\n");
        }else{
            printf("a\n");
            buf[0] = '\0';
            printf("b\n");
            close(pipe3[1]);
            printf("c\n\n");

            dup2(pipe3[0], STDIN_FILENO);
            read(pipe3[0], buf, sizeof(buf));
            close(pipe3[0]);

            printf("-SORT BUFF-\n%s\n\n", buf);

            //dup2(pipe2[1], STDOUT_FILENO);
            close(pipe2[1]);

            execlp("sort","sort",(char *)0);

            printf("-SORTED BUFF-\n%s\n\n", buf);
            exit(0);
        }
        // wait second child exec
        wait(NULL);

        //printf("%s\n", buf);
        exit(0);
    }

    // wait child exec
    //wait(NULL);

    int status;
    pid_t pid;
    int n = 2;
    while (n > 0){
        pid = wait(&status);
        printf("-SORTED BUFF-\n%s\n\n", buf);
        --n;
    }
    // parent read pipe 2 and print
    if (childpid[0] != 0){
        printf("asd\n");
        buf[0] = '\0';
        dup2(pipe2[0], STDIN_FILENO);
        read(pipe2[0], buf, sizeof(buf));
        close(pipe2[0]);
        printf("-SORTED BUFF-\n%s\n\n", buf);
    }
    return 0;
}

**Thought 3**

2 个答案:

答案 0 :(得分:1)

目的是让父文件打开文件并将其写入管道。在同一时间,我们有一个孩子,创建第二个管道并阅读它。而且在同一时间,我们又有了第二个孩子。

我们需要2个孩子和2个管道。第一个父母等待第一个孩子,第一个孩子等待第二个孩子。

我不知道它是否完美,因为我无法测试,这件事情之王非常复杂:

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

static int wait_and_return(pid_t pid) {
  int status;
  if (waitpid(pid, &status, 0) == -1) {
    perror("waitpid()");
    return 1;
  }
  return status;
}

static pid_t create_pipe_and_fork(int fd_pipe[2]) {
  if (pipe(fd_pipe) == -1) {
    perror("pipe()");
    return -1;
  }

  pid_t pid = fork();
  if (pid == -1) {
    close(fd_pipe[0]);
    close(fd_pipe[1]);
    perror("fork()");
    return -1;
  }

  return pid;
}

static int exec_sort(int fd_in, int fd_out) {
  if (dup2(fd_in, STDIN_FILENO) == -1 || dup2(fd_out, STDOUT_FILENO) == -1) {
    close(fd_in);
    close(fd_out);
    perror("dup2()");
    return 1;
  }

  close(fd_in);
  close(fd_out);

  execlp("sort", "sort", (char *)NULL);
  perror("execlp()");
  return 1;
}

static int child(int fd) {
  int fd_pipe[2];
  pid_t pid = create_pipe_and_fork(fd_pipe);
  if (pid == -1) {
    close(fd);
    return 1;
  }

  if (pid != 0) {
    close(fd);
    close(fd_pipe[1]);
    char buf[4048];
    ssize_t ret;
    while ((ret = read(fd_pipe[0], buf, sizeof buf)) > 0) {
      if (ret > INT_MAX) {
        close(fd_pipe[0]);
        wait_and_return(pid);
        return 1;
      }
      printf("%.*s", (int)ret, buf);
    }

    close(fd_pipe[0]);

    return wait_and_return(pid);
  } else {
    close(fd_pipe[0]);

    return exec_sort(fd, fd_pipe[1]);
  }
}

int main(int argc, char **argv) {
  if (argc != 2) {
    fprintf(stderr, "wrong argument\n");
    return 1;
  }

  int fd_pipe[2];
  pid_t pid = create_pipe_and_fork(fd_pipe);
  if (pid == -1) {
    return 1;
  }

  if (pid != 0) {
    close(fd_pipe[0]);

    FILE *file = fopen(argv[1], "r");
    if (file == NULL) {
      perror("fopen():");
      close(fd_pipe[1]);
      wait_and_return(pid);
      return 1;
    }

    char buf[4048];
    size_t ret;
    while ((ret = fread(buf, sizeof *buf, sizeof buf / sizeof *buf, file))) {
      write(fd_pipe[1], buf, ret);
    }
    fclose(file);

    close(fd_pipe[1]);

    return wait_and_return(pid);
  } else {
    close(fd_pipe[1]);

    return child(fd_pipe[0]);
  }
}

可以反转主要和最后一个孩子的角色,因此主要读取结果,孩子将打开文件。我让你试试。

答案 1 :(得分:1)

第1部分

在您的父代码中,您有:

dup2(pipe1[1],STDOUT_FILENO);
write(pipe1[1], buf, sizeof(buf));
close(pipe1[1]);

这在多个方面存在问题:

  1. 父母的标准输出现在是用于向儿童发送信息的管道的写入端。这意味着父母必须打开文件或终端或其他东西,以便将sort的结果写入其原始标准输出。
  2. 当您close(pipe1[1])时,管道仍然有一个打开的文件描述符(父级的标准输出),因此sort永远不会在管道上获得EOF。< / LI>
  3. 您没有记录您阅读的数据量,因此您不知道应该写多少数据。除非您知道文件大于1024字节,否则您可能会将垃圾写入管道。您应捕获从文件读取的数据量,并仅将大量数据写入管道。您应该考虑确保信息以换行符结束。
  4. 由于孩子要wait()完成,但孩子不知道其输入是否完整,否则就会出现死锁。然后,您可以使用代码来读取输入数据,但由于dup2()而无法清除您要写入的位置。

    • 第一阶段修复:删除已标识的dup2()

    烦恼死锁

    原则上,整个设计只能起作用,因为sort在写入任何输出之前必须读取所有输入。如果您有一个awksed之类的命令可以在完成读取输入之前编写输出,那么您的双向管道方案在大量数据上将无法正常工作。当父级仍在尝试写入并发现其管道缓冲区已满时,子级可能会填充管道缓冲区(并且无法再向其写入)。两个进程都会陷入写入,等待另一个进行读取。有很多方法 - select()poll(),多个主题等等 - 但它们超出了您想要或现在需要处理的范围。

    此外,您的程序将输入限制为sort至最多1024个字节。这还不足以填充任何管道缓冲区,这意味着除非执行的命令增加了它必须写回的数据量与读入的数据相比 - 例如,如果您将URL发送到获取来自这些网址的数据 - 然后您就不会遇到死锁。

    第2部分

    子代码似乎从管道中读取数据,然后启动sort(但sort没有任何内容可供阅读),并且似乎期待execlp()回来。代码只需要将管道的正确末端连接到标准输入和输出,关闭所有管道文件描述符,然后执行sort。如果execlp()返回,则失败 - 报告错误。

    • 第二阶段修复:简化子进程,让sort进行阅读和写作。

    工作代码

    留下了许多评论的位。添加了关键错误检查。例如,在执行任何其他操作之前,请检查命令行是否正确。通常,您在分叉前打开文件;这一次,最好不要这样做。报告标准错误的错误。

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    
    int main (int argc, char **argv){
        int pipe1[2];
        int pipe2[2];
        pid_t childpid;
        FILE *fdin;
    
        if (argc != 2)
        {
            fprintf(stderr, "Usage: %s file\n", argv[0]);
            exit(1);
        }
    
        pipe(pipe1);
        pipe(pipe2);
    
        // error handling
        if ((childpid = fork()) == -1){
            perror("fork");
            exit(1);
        }
    
        // parent load file, write to pipe1
        if (childpid != 0){
            //long fsize;
            char buf[1024];
            close(pipe1[0]);
            close(pipe2[1]);
    
            fdin = fopen(argv[1], "r");
            if (fdin == 0)
            {
                fprintf(stderr, "%s: failed to open file '%s'\n", argv[0], argv[1]);
                exit(1);
            }
    
            //fseek(fdin, 0, SEEK_END);
            //fsize = ftell(fdin);
            //fseek(fdin, 0, SEEK_SET);
    
            int nbytes = fread(buf, 1, sizeof(buf), fdin);
            if (nbytes <= 0)
            {
                fprintf(stderr, "%s: no data in file '%s'\n", argv[0], argv[1]);
                exit(1);
            }
            fclose(fdin);
    
            //dup2(pipe1[1],STDOUT_FILENO);
            write(pipe1[1], buf, nbytes);
            close(pipe1[1]);
        }
        else if (childpid == 0){
            //char buf[1024];
            close(pipe1[1]);
            close(pipe2[0]);
            dup2(pipe2[1], STDOUT_FILENO);
            dup2(pipe1[0], STDIN_FILENO);
            close(pipe2[1]);
            close(pipe1[0]);
    
            //read(pipe1[0], buf, sizeof(buf));
            //close(pipe1[0]);
    
            //printf("%s\n\n", buf);
    
            //dup2(pipe2[1], STDOUT_FILENO);
            //close(pipe2[1]);
    
            execlp("sort", "sort",(char *)0);
    
            fprintf(stderr, "%s: failed to exec 'sort'\n", argv[0]);
            exit(1);
        }
    
        // wait child
        wait(NULL);
    
        // parent read pipe 2 and print
        if (childpid != 0){
            char buf[1024];
            int nbytes;
            while ((nbytes = read(pipe2[0], buf, sizeof(buf))) > 0)
                printf("%.*s", nbytes, buf);
        }
        return 0;
    }
    

    请注意在两次读取操作中仔细捕获大小。

    考虑输入文件:

    Harlequin
    Preposterous
    Animagus
    Zealot
    Queensbury Rules
    Quaternion
    Hedwig
    Tensor
    Tenser
    

    我得到的输出是:

    Animagus
    Harlequin
    Hedwig
    Preposterous
    Quaternion
    Queensbury Rules
    Tenser
    Tensor
    Zealot
    

    这对我来说是正确的。