实现在C流水线。什么是做到这一点的最好办法? (自己的Linux壳) [英] Implementing pipelining in c. What would be the best way to do that? (Own linux shell)

查看:158
本文介绍了实现在C流水线。什么是做到这一点的最好办法? (自己的Linux壳)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想不出任何方法来实现在C,将实际工作流水线。这就是为什么我决定在这里写英寸我不得不说,我知道该怎么办管/叉/ mkfifo子的工作。我见过实施2-3管道的大量例子。这很容易。我的问题开始,当我已经有了实现的外壳,和管道数是未知的。

I can't think of any way to implement pipelining in c that would actually work. That's why I've decided to write in here. I have to say, that I understand how do pipe/fork/mkfifo work. I've seen plenty examples of implementing 2-3 pipelines. It's easy. My problem starts, when I've got to implement shell, and pipelines count is unknown.

我现在得:
例如:

What I've got now: eg.

ls -al | tr a-z A-Z | tr A-Z a-z | tr a-z A-Z

我这样的转换线进入这样的事情:

I transform such line into something like that:

array[0] = {"ls", "-al", NULL"}
array[1] = {"tr", "a-z", "A-Z", NULL"}
array[2] = {"tr", "A-Z", "a-z", NULL"}
array[3] = {"tr", "a-z", "A-Z", NULL"}

所以,我可以使用

So I can use

execvp(array[0],array)

以后。

Untli现在,我相信一切都OK。问题开始,当我尝试这些功能的输入/输出重定向到海誓山盟。

Untli now, I believe everything is OK. Problem starts, when I'm trying to redirect those functions input/output to eachother.

下面就是我正在做的是:

Here's how I'm doing that:

    mkfifo("queue", 0777);

    for (i = 0; i<= pipelines_count; i++) // eg. if there's 3 pipelines, there's 4 functions to execvp
    {
    int b = fork();             
    if (b == 0) // child
        {           
        int c = fork();

        if (c == 0) 
        // baby (younger than child) 
        // I use c process, to unblock desc_read and desc_writ for b process only
        // nothing executes in here
            {       
            if (i == 0) // 1st pipeline
                {
                int desc_read = open("queue", O_RDONLY);
                // dup2 here, so after closing there's still something that can read from 
                // from desc_read
                dup2(desc_read, 0); 
                close(desc_read);           
                }

            if (i == pipelines_count) // last pipeline
                {
                int desc_write = open("queue", O_WRONLY);
                dup2(desc_write, 0);
                close(desc_write);                              
                }

            if (i > 0 && i < pipelines_count) // pipeline somewhere inside
                {
                int desc_read = open("queue", O_RDONLY);
                int desc_write = open("queue", O_WRONLY);
                dup2(desc_write, 1);
                dup2(desc_read, 0);
                close(desc_write);
                close(desc_read);
                }               
            exit(0); // closing every connection between process c and pipeline             
            }
        else
        // b process here
        // in b process, i execvp commands
        {                       
        if (i == 0) // 1st pipeline (changing stdout only)
            {   
            int desc_write = open("queue", O_WRONLY);               
            dup2(desc_write, 1); // changing stdout -> pdesc[1]
            close(desc_write);                  
            }

        if (i == pipelines_count) // last pipeline (changing stdin only)
            {   
            int desc_read = open("queue", O_RDONLY);                                    
            dup2(desc_read, 0); // changing stdin -> pdesc[0]   
            close(desc_read);           
            }

        if (i > 0 && i < pipelines_count) // pipeline somewhere inside
            {               
            int desc_write = open("queue", O_WRONLY);       
            dup2(desc_write, 1); // changing stdout -> pdesc[1]
            int desc_read = open("queue", O_RDONLY);                            
            dup2(desc_read, 0); // changing stdin -> pdesc[0]
            close(desc_write);
            close(desc_read);                               
            }

        wait(NULL); // it wait's until, process c is death                      
        execvp(array[0],array);         
        }
        }
    else // parent (waits for 1 sub command to be finished)
        {       
        wait(NULL);
        }       
    }

感谢。

推荐答案

Patryk,你为什么要使用一个FIFO,而且同一个fifo为管道的每个阶段?

Patryk, why are you using a fifo, and moreover the same fifo for each stage of the pipeline?

在我看来,你需要在每个阶段之间的管道。所以流动会是这样的:

It seems to me that you need a pipe between each stage. So the flow would be something like:

Shell             ls               tr                tr
-----             ----             ----              ----
pipe(fds);
fork();  
close(fds[0]);    close(fds[1]);
                  dup2(fds[0],0); 
                  pipe(fds);
                  fork();         
                  close(fds[0]);   close(fds[1]);  
                  dup2(fds[1],1);  dup2(fds[0],0);
                  exex(...);       pipe(fds);
                                   fork();     
                                   close(fds[0]);     etc
                                   dup2(fds[1],1);
                                   exex(...);  

这在每个叉状壳(接近,dup2,管等)上运行的序列似乎是一个功能(服用的名称和期望的过程的参数)。需要注意的是,直到 EXEC在每个通话,外壳的一个分支副本正在运行。

The sequence that runs in each forked shell (close, dup2, pipe etc) would seem like a function (taking the name and parameters of the desired process). Note that up until the exec call in each, a forked copy of the shell is running.

编辑:

Patryk:

Also, is my thinking correct? Shall it work like that? (pseudocode): 
start_fork(ls) -> end_fork(ls) -> start_fork(tr) -> end_fork(tr) -> 
start_fork(tr) -> end_fork(tr) 

我不知道你所说的start_fork和end_fork的意思。你是说 LS 运行完成之前 TR 开始?这是不是真的什么是上图中的意思。你的shell不会等待 LS 启动 TR 之前完成。它启动的所有进程的顺序管道,建立标准输入标准输出为每一个这样的过程连在了一起,标准输出 LS 标准输入 TR ; 标准输出 TR 标准输入接下来<$ C的$ C> TR 。这正是dup2调用正在做的。

I'm not sure what you mean by start_fork and end_fork. Are you implying that ls runs to completion before tr starts? This isn't really what is meant by the diagram above. Your shell will not wait for ls to complete before starting tr. It starts all of the processes in the pipe in sequence, setting up stdin and stdout for each one so that the processes are linked together, stdout of ls to stdin of tr; stdout of tr to stdin of the next tr. That is what the dup2 calls are doing.

在该进程中运行的操作系统(调度),但显然,如果 TR 从空运行,并读确定的顺序标准输入它必须等待(以块),直至preceding进程写的东西到管道。这很可能是 LS 会在 TR 运行完成,甚至从标准输入<读/ code>,但它同样有可能它不会。例如,如果链中的第一个命令是什么,不断跑和生产一路输出,在管道中的第二个会被调度不时到prcess无论第一沿管道发送。

The order in which the processes run is determined by the operating system (the scheduler), but clearly if tr runs and reads from an empty stdin it has to wait (to block) until the preceding process writes something to the pipe. It is quite possible that ls might run to completion before tr even reads from its stdin, but it is equally possible that it wont. For example if the first command in the chain was something that ran continually and produced output along the way, the second in the pipeline will get scheduled from time to time to prcess whatever the first sends along the pipe.

。希望澄清事情有点: - )

Hope that clarifies things a little :-)

这篇关于实现在C流水线。什么是做到这一点的最好办法? (自己的Linux壳)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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