c中的pipe()和fork() [英] pipe() and fork() in c

查看:224
本文介绍了c中的pipe()和fork()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要创建两个子进程.一个孩子需要运行命令"ls -al",并将其输出重定向到下一个孩子进程的输入,该子进程又将在其输入数据上运行命令"sort -r -n -k 5".最后,父进程需要读取该数据(已排序的数据)并将其显示在终端中.终端中的最终结果(执行程序时)应与我直接在外壳中输入以下命令相同:"ls -al | sort -r -n -k 5".为此,我需要使用以下方法:pipe(),fork(),execlp().

I need to create two child processes. One child needs to run the command "ls -al" and redirect its output to the input of the next child process, which in turn will run the command "sort -r -n -k 5" on its input data. Finally, the parent process needs to read that (data already sorted) and display it in the terminal. The final result in the terminal (when executing the program) should be the same as if I entered the following command directly in the shell: "ls -al | sort -r -n -k 5". For this I need to use the following methods: pipe(), fork(), execlp().

我的程序可以编译,但是没有获得所需的输出到终端.我不知道怎么了这是代码:

My program compiles, but I don't get the desired output to the terminal. I don't know what is wrong. Here is the code:

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

int main()
{
    int fd[2];
    pid_t ls_pid, sort_pid;
    char buff[1000];

    /* create the pipe */
    if (pipe(fd) == -1) {
        fprintf(stderr, "Pipe failed");
        return 1;
    }

    /* create child 2 first */
    sort_pid = fork();
    if (sort_pid < 0) {                         // error creating Child 2 process
        fprintf(stderr, "\nChild 2 Fork failed");
        return 1;
    }
    else if(sort_pid > 0) {                     // parent process

        wait(NULL);                             // wait for children termination

        /* create child 1 */
        ls_pid = fork();
        if (ls_pid < 0) {                       // error creating Child 1 process
            fprintf(stderr, "\nChild 1 Fork failed");
            return 1;
        }
        else if (ls_pid == 0) {                 // child 1 process
            close(1);                           // close stdout
            dup2(fd[1], 1);                     // make stdout same as fd[1]
            close(fd[0]);                       // we don't need this end of pipe
            execlp("bin/ls", "ls", "-al", NULL);// executes ls command
        }

        wait(NULL);
        read(fd[0], buff, 1000);                // parent reads data 
        printf(buff);                           // parent prints data to terminal   
    }
    else if (sort_pid == 0) {                   // child 2 process
        close(0);                               // close stdin
        dup2(fd[0], 0);                         // make stdin same as fd[0]
        close(fd[1]);                           // we don't need this end of pipe
        execlp("bin/sort", "sort", "-r", "-n", "-k", "5", NULL); // executes sort operation
    }

    return 0;
}

推荐答案

您的父进程wait用于在创建ls进程之前完成排序过程.

Your parent process waits for the sort process to finish before creating the ls process.

排序过程需要先读取其输入,然后才能完成.而且它的输入来自ls,直到wait之后才开始.死锁.

The sort process needs to read its input before it can finish. And its input is coming from the ls that won't be started until after the wait. Deadlock.

您需要先创建两个进程,然后再创建两个wait.

You need to create both processes, then wait for both of them.

此外,您的文件描述符操作也不正确.在这对通话中:

Also, your file descriptor manipulations aren't quite right. In this pair of calls:

close(0);
dup2(fd[0], 0);

关闭是多余的,因为dup2将自动关闭现有fd 0(如果有的话).您应该在dup2之后执行close(fd[0]),因此只有一个文件描述符绑定到管道的那一端.而且,如果您想真正强大起来,则应该已经对fd[0]==0进行了测试,在这种情况下,请跳过dup2并关闭.

the close is redundant, since dup2 will automatically close the existing fd 0 if there is one. You should do a close(fd[0]) after ther dup2, so you only have one file descriptor tied to that end of the pipe. And if you want to be really robust, you should test wither fd[0]==0 already, and in that case skip the dup2 and close.

将所有这些都应用到另一个dup2.

Apply all of that to the other dup2 also.

然后是父进程保持管道打开的问题.我想说,在将管道传递给孩子之后,您应该关闭管道的两端,但是在最后一个wait之后,您有read怪异的read ...不知道为什么会在那里.如果ls|sort管道已正确运行,则该管道之后将为空,因此将没有任何内容可读取.无论如何,您绝对需要在父级中关闭fd[1],否则排序过程将无法完成,因为在关闭所有编写器之前,管道不会指示EOF.

Then there's the issue of the parent process holding the pipe open. I'd say you should close both ends of the pipe in the parent after you've passed them on to the children, but you have that weird read from fd[0] after the last wait... I'm not sure why that's there. If the ls|sort pipeline has run correctly, the pipe will be empty afterward, so there will be nothing to read. In any case, you definitely need to close fd[1] in the parent, otherwise the sort process won't finish because the pipe won't indicate EOF until all writers are closed.

奇怪的read之后是printf,由于读取缓冲区不会被'\0'终止,因此它可能会崩溃.

After the weird read is a printf that will probably crash, since the read buffer won't be '\0'-terminated.

使用execlp的要点是它会为您执行$PATH查找,因此您不必指定/bin/.我的第一次测试失败,因为我的排序在/usr/bin/中.为什么不用硬编码路径?

And the point of using execlp is that it does the $PATH lookup for you so you don't have to specify /bin/. My first test run failed because my sort is in /usr/bin/. Why hardcode paths when you don't have to?

这篇关于c中的pipe()和fork()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆