我正在学习操作系统课程,而且当你有叉子时,我很难用dup2重定向输入。我写了这个小程序试图让它有意义,但我没有成功地将一个大孩子的输出传给一个孩子。我试图模仿unix命令:ps -A | wc -l。我是Unix的新手,但我相信这应该算上我得到的正在运行的进程列表的行。所以我的输出应该是一个数字。
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <iostream>
using namespace std;
int main( int argc, char *argv[] ) {
char *searchArg = argv[ 1 ];
pid_t pid;
if ( ( pid = fork() ) > 0 ) {
wait( NULL );
cout << "Inside parent" << endl;
}
else if ( pid == 0 ) {
int fd1[ 2 ];
pipe( fd1 );
cout << "Inside child" << endl;
if ( pid = fork() > 0 ) {
dup2( fd1[ 0 ], 0 );
close( fd1[ 0 ] );
execlp( "/bin/wc", "-l", NULL );
}
else if ( pid == 0 ) {
cout << "Inside grand child" << endl;
execlp( "/bin/ps", "-A", NULL );
}
}
return 0;
}
我在上面的代码中没有它,但这是我对事情应该如何下降的猜测:
问题:我在哪里将其重定向到?我知道它应该是文件描述符之一,但应该在哪里重定向,以便wc可以处理它?</ p>
问题:wc如何收到输出?通过execlp参数?或者操作系统是否检查了其中一个文件描述符?
关闭哪一项并让wc接收和处理ps的输出?我一直认为这需要被认为是倒退,因为ps需要将其输出提供给wc ......但这似乎没有意义,因为并行处理子孙和孙子。
答案 0 :(得分:4)
首先,让我们修复你的代码,以便我们为它添加更多的错误检查,以便它可以工作;用下面的位替换:
else if ( pid == 0 ) {
int fd1[ 2 ];
pipe( fd1 );
cout << "Inside child" << endl;
if ( pid = fork() > 0 ) {
if (dup2( fd1[ 0 ] , 0 ) < 0) {
cerr << "Err dup2 in child" << endl;
}
close( fd1[ 0 ] );
close( fd1[ 1 ] ); // important; see below
// Note: /usr/bin, not /bin
execlp( "/usr/bin/wc", "wc", "-l", NULL );
cerr << "Err execing in child" << endl;
}
else if ( pid == 0 ) {
cout << "Inside grand child" << endl;
if (dup2( fd1[ 1 ] , 1 ) < 0) {
cerr << "Err dup2 in gchild" << endl;
}
close( fd1[ 0 ] );
close( fd1[ 1 ] );
execlp( "/bin/ps", "ps", "-A", NULL );
cerr << "Err execing in grandchild" << endl;
}
}
现在,您的问题:
问题:我在哪里将其重定向到?我知道它应该是文件描述符之一,但应该在哪里重定向,以便wc可以处理它?</ p>
文件描述符0
,1
和2
在Unix中很特殊,因为它们是标准输入,标准输出和标准错误。 wc
从标准输入读取,因此dup
0
的任何内容均为exec
。
问题:wc如何收到输出?通过execlp参数?或者操作系统是否检查了其中一个文件描述符?
通常,在进程将其图像与exec
交换后,它将具有CLOSE_ON_EXEC
之前的所有打开文件描述符。 (除了那些设置了dup2
标志的描述符,但暂时忽略它们)因此,如果你0
wc
,close
将读取它。
关闭哪一项并让wc接收和处理ps的输出?
如上图所示,你可以关闭孩子和孙子的管道的两端,这样就可以了。事实上,标准练习会建议您这样做。但是,在这个具体示例中唯一真正必要的dup
行是我评论为&#34; important&#34; - 关闭了孩子中管道的写端。
这个想法是这样的:孩子和大孩子在他们开始时都会打开管道的两端。现在,通过wc
我们已将wc
连接到管道的读取端。 ps -A
将继续吸吮该管道,直到管道写入端的所有描述符都关闭,此时它会看到它到达文件的末尾并停止。现在,在祖母中,我们可以逃避不关闭任何东西,因为1
不会对任何描述符做任何事情,而是写入描述符ps -A
,并且fd[0]
之后1}}完成吐出关于某些进程的东西,它将退出,关闭它拥有的所有东西。在孩子中,我们并不需要关闭wc
中存储的读取描述符,因为0
不会尝试读取除了描述符wc
之外的任何内容。但是,我们确实需要关闭子管道的写入端,否则close
就会坐在那里,管道永远不会完全关闭。
正如您所看到的,为什么我们并不真正需要任何wc
行,除了标有&#34;重要&#34;取决于ps
和dup2
将如何表现的详细信息,因此标准做法是关闭您未完全使用的管道的末端,并保持开放结束仅使用一个描述符。由于您在两个流程中都使用close
,这意味着上述四个execlp
语句。
编辑:更新了{{1}}的参数。