在C中实现流水线。做到这一点的最佳方法是什么?
我想不出任何可行的方法来在c中实现流水线工作。这就是为什么我决定在这里写的原因。我必须说,我了解管道/叉子/
mkfifo的工作方式。我已经看到了很多实施2-3条管道的示例。这简单。当我必须实现Shell时,我的问题就开始了,而管道数量是未知的。
我现在所拥有的:例如。
ls -al | tr a-z A-Z | tr A-Z a-z | tr a-z A-Z
我将这样的行转换为类似的内容:
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"}
所以我可以用
execvp(array[0],array)
稍后的。
现在,我相信一切都会好起来的。当我尝试将输入/输出的功能重定向到彼此时,问题就开始了。
这是我的做法:
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?
在我看来,每个阶段之间都需要一个管道。因此流程如下所示:
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(...);
在每个分叉的外壳程序(close,dup2,pipe等)中运行的序列看起来像一个函数(带有所需进程的名称和参数)。请注意,直到exec
每个调用之前,shell的分支副本都在运行。
编辑:
帕特里克:
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
?这并不是上面的图真正的意思。您的外壳程序将ls
在启动之前不等待完成tr
。它开始的所有过程的按顺序配管,设置stdin
和stdout
为每一个,以使工艺连接在一起,stdout
的ls
到stdin
的tr
;
stdout
的tr
到stdin
了下tr
。这就是dup2调用正在执行的操作。
进程的运行顺序由操作系统(调度程序)确定,但很显然,如果进程正在tr
运行并从空读取,stdin
则必须等待(阻塞),直到前一个进程向管道中写入内容为止。甚至有ls
可能tr
从它的读取之前就完成了stdin
,但是也有可能不会完成。例如,如果链中的第一个命令是连续运行的并且一直沿途产生输出,那么无论第一个命令沿管道发送什么,管道中的第二个命令都会不定期地进行处理。
希望能使事情澄清一些:-)
以上是 在C中实现流水线。做到这一点的最佳方法是什么? 的全部内容, 来源链接: utcz.com/qa/427022.html