我似乎无法找到如何通过三个子进程管道数据的良好解释。我基本上想要这样做:
ls -al / | tr a-j A-J | tr k-z K-Z
我已经能够设置两个子进程来模拟命令的前两部分,并且输出正确。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
main()
{
int pi[2];
pipe(pi);
// First child
if ( fork() == 0 )
{
close(pi[0]);
dup2(pi[1], 1);
close(pi[1]);
execlp( "ls", "ls", "-al", NULL );
}
// Second child
if ( fork() == 0 )
{
close(pi[1]);
dup2(pi[0], 0);
close(pi[0]);
execlp( "tr", "tr", "a-j", "A-J", NULL );
}
// Close parent's copy of pipe
close(pi[0]);
close(pi[1]);
wait(NULL);
}
我能想到将输出传递给第三个进程的唯一方法是创建第二个管道。然后我会使用第二个管道将数据从第二个子项传递给第三个子项。不幸的是,当我尝试这样做时,我根本没有输出。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
main()
{
// Create the two pipes
int pi[2];
pipe(pi);
int pi2[2];
pipe(pi2);
// First child
if ( fork() == 0 )
{
// Set up the first pipe to be written to
close(pi[0]);
dup2(pi[1], 1);
close(pi[1]);
execlp( "ls", "ls", "-al", NULL );
}
// Second child
if ( fork() == 0 )
{
// Set up first pipe to be read from
close(pi[1]);
dup2(pi[0], 0);
close(pi[0]);
// Set up second pipe to be written to
close(pi2[0]);
dup2(pi2[1], 1);
close(pi2[1]);
execlp( "tr", "tr", "a-j", "A-J", NULL );
}
// Third child
if ( fork() == 0 )
{
// Set up second pipe to be read from
close(pi2[1]);
dup2(pi2[0], 0);
close(pi2[0]);
execlp( "tr", "tr", "k-z", "K-Z", NULL );
}
// Close parent's copy of first and second pipes
close(pi[1]);
close(pi[0]);
close(pi2[1]);
close(pi2[0]);
wait(NULL);
}
我不完全确定从哪里开始。是编码错误,还是错误的方法?
编辑:我发现了问题。管道(pi)上的端点被复制到子进程中,永远不会关闭。解决方案是在分叉第三个子节点之前关闭父节点中的端点,这样它就不会获得自己的副本,或者关闭端点的副本。
我已经在第三个孩子面前关闭了端点。我也没有制造烟斗&#34; pi2&#34;直到第一个实际使用它的孩子之后。我认为理论上我应该关闭管道的端点&#34; pi2&#34;在第一个孩子,但在实践中它仍然有效。将管道的创建移动到第一个子项之后将消除任何问题。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
main()
{
// Create the two pipes
int pi[2];
pipe(pi);
int pi2[2];
// First child
if ( fork() == 0 )
{
// Set up the first pipe to be written to
// and close the unneeded pipe endpoints
close(pi[0]);
dup2(pi[1], 1);
close(pi[1]);
execlp( "ls", "ls", "-al", NULL );
}
// Don't open the second pipe until it's needed
// so extra endpoints don't need to be closed
pipe(pi2);
// Second child
if ( fork() == 0 )
{
// Set up first pipe to be read from
// and close the unneeded pipe endpoints
close(pi[1]);
dup2(pi[0], 0);
close(pi[0]);
// Set up second pipe to be written to
// and close the unneeded pipe endpoints
close(pi2[0]);
dup2(pi2[1], 1);
close(pi2[1]);
execlp( "tr", "tr", "a-j", "A-J", NULL );
}
// Close original pipe endpoints so they aren't
// duplicated into the third child (where they would
// need to be closed).
close(pi[1]);
close(pi[0]);
// Third child
if ( fork() == 0 )
{
// Set up second pipe to be read from
// and close the unneeded pipe endpoints
close(pi2[1]);
dup2(pi2[0], 0);
close(pi2[0]);
execlp( "tr", "tr", "k-z", "K-Z", NULL );
}
// Close parent's copy of second pipes
close(pi2[1]);
close(pi2[0]);
wait(NULL);
}