我正在学习操作系统类(class),当你有 fork 时,我很难用 dup2 重定向输入。我编写了这个小程序来尝试了解它,但是我没有成功地将孙子的输出传递给 child 。我试图模仿 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 可以处理它?
问题:wc 如何接收输出?通过execlp参数?或者操作系统是否检查文件描述符之一?
其中哪一个是关闭的并保持打开状态,以便 wc 接收和处理 ps 的输出?我一直认为这需要向后考虑,因为 ps 需要将其输出提供给 wc ……但这似乎没有意义,因为子和孙子都是并行处理的。
最佳答案
首先,让我们修复您的代码,以便我们向它添加更多的错误检查,使其工作;用以下内容替换底部位:
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;
}
}
现在,你的问题:文件描述符
0
, 1
, 和 2
Unix 中的特殊之处在于它们是标准输入、标准输出和标准错误。 wc
从标准输入读取,所以不管是 dup
编辑至 0
.通常,在进程用
exec
换出其镜像后,它将拥有之前所有的打开文件描述符 exec
. (除了那些设置了 CLOSE_ON_EXEC
标志的描述符,但暂时忽略它)因此,如果你 dup2
有事要0
,然后 wc
会读。如上所示,您可以关闭子代和孙代管道的两端,这样就可以了。事实上,标准做法会建议您这样做。然而,唯一真正需要的
close
这个特定示例中的那一行是我评论为“重要”的那一行 - 即关闭子进程中管道的写端。这个想法是这样的: child 和孙子在开始时都打开管道的两端。现在,通过
dup
我们已连接 wc
到管道的读取端。 wc
将继续吸入该管道,直到管道写入端的所有描述符都关闭,此时它将看到它到达文件末尾并停止。现在,在孙子中,我们可以不关闭任何东西,因为 ps -A
不会对任何描述符做任何事情,而是写入描述符 1
,以及之后 ps -A
完成吐出有关它将退出的某些进程的内容,关闭它拥有的所有内容。在子进程中,我们实际上并不需要关闭存储在 fd[0]
中的读取描述符。因为 wc
除了描述符 0
之外,不会尝试读取任何内容.但是,我们确实需要关闭子进程中管道的写端,否则 wc
只是坐在那里,管子永远不会完全关闭。正如你所看到的,为什么我们真的不需要任何
close
的原因除了标记为“重要”的那一行,取决于 wc
的详细信息和 ps
会起作用,所以标准做法是关闭您没有完全使用的管道的末端,并保持打开您只使用一个描述符的末端。由于您使用的是 dup2
在这两个进程中,这意味着四个 close
声明如上。编辑:将参数更新为
execlp
.
关于unix - dup2 和 fork 怎么一起用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8860895/