如何一起使用 dup2 和 fork?
我正在学习操作系统课程,当你有 fork 时,我很难理解如何使用 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;
}
我在上面的代码中没有它,但这是我对事情应该如何进行的猜测:
- 我们需要重定向命令 ps -A 的标准输出(通常打印到屏幕上的内容,对吗?)以便 wc -l命令可以使用它来计算行数。
- 可以使用 dup2 重定向此标准输出,例如 dup2( ?, 1 ) ,这意味着将标准输出重定向到 ?。然后你关闭?
问题:我应该将其重定向到哪里?我知道它应该是文件描述符之一,但是应该将其重定向到哪里以便 wc 可以处理它?
- wc 以某种方式接收标准输出。
问题:wc 如何接收输出?通过 execlp 参数?或者操作系统是否检查文件描述符之一?
- 执行wc -l。
其中哪一个被关闭并保持打开状态以供 wc 接收和处理 ps 的输出?我一直认为这需要向后考虑,因为 ps 需要将其输出提供给 wc...但这似乎没有意义,因为子级和孙级都是并行处理的。
I'm taking an operating systems course and I'm having a hard time how input is redirected with dup2 when you have forks. I wrote this small program to try and get a sense for it but I wasn't successful in passing the output of a grand-child to a child. I am trying to mimick the unix command: ps -A | wc -l. I'm new to Unix, but I believe this should count the lines of the list of running processes I get. So my output should be a single number.
#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;
}
I don't have it in the code above, but here is my guess on how things should go down:
- We need to redirect standard output of command ps -A (whatever is usually printed to the screen, correct?) so that the wc -l command can use it to count the lines.
- This standard output can be redirected using dup2, like dup2( ?, 1 ) which means redirect standard output to ?. Then you close ?.
Question: Where do I redirect it to? I know it should be one of the file descriptors, but where should it be redirected so that wc can process it?
- wc somehow receives the standard output.
Question: How does wc receive the output? Through an execlp parameter? Or does the operating system check one of the file descriptors?
- Execute wc -l.
Which one of these is closed and left open for wc to receive and process ps's output? I keep thinking this needs to be thought of backwards since ps needs to give its output to wc...but that doesn't seem to make sense since both child and grand-child are being processed in parallel.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
首先,让我们修复您的代码,以便为它添加一点点错误检查,以便它能够工作;将底部的部分替换为:
现在,您的问题:
问题:我将其重定向到哪里?我知道它应该是文件描述符之一,但是应该将其重定向到哪里以便 wc 可以处理它?</p>
文件描述符
0
、1
和2
在 Unix 中很特殊,因为它们是标准输入、标准输出和标准错误。wc
从标准输入读取,因此无论什么都dup
为0
。问题:wc如何接收输出?通过 execlp 参数?或者操作系统是否检查文件描述符之一?
一般来说,在进程使用
exec
交换其映像后,它将拥有在exec
之前拥有的所有打开的文件描述符。 (除了那些设置了CLOSE_ON_EXEC
标志的描述符,但现在忽略它)因此,如果您将某些内容dup2
为0
,则wc
将读取它。其中哪一个已关闭并保持打开状态以供 wc 接收和处理 ps 的输出?
如上所示,您可以在子级和孙级中关闭管道的两端,这样就可以了。事实上,标准做法会建议您这样做。然而,在这个特定示例中,唯一真正必要的
close
行是我评论为“重要”的那行 - 即关闭子进程中管道的 write 端。这个想法是这样的:子进程和孙进程在启动时管道的两端都打开。现在,通过 dup 我们已将 wc 连接到管道的读取端。 wc 将继续吸收该管道,直到管道写入端的所有描述符都关闭,此时它会看到它到达文件末尾并停止。现在,在孙子中,我们可以不关闭任何东西,因为
ps -A
不会对任何描述符执行任何操作,而是写入描述符1
>,在ps -A
完成吐出有关某些进程的内容后,它将退出,关闭它拥有的所有内容。在子进程中,我们实际上并不需要关闭存储在fd[0]
中的读取描述符,因为wc
不会尝试从描述符以外的任何内容读取<代码>0。但是,我们确实需要关闭子级中管道的写入端,否则wc
将与永远不会完全关闭的管道一起坐在那里。正如您所看到的,除了标记为“重要”的行之外,我们实际上不需要任何
close
行的原因取决于wc
的详细信息> 和ps
将会起作用,因此标准做法是关闭未完全使用的管道末端,并保持仅使用一个描述符的末端打开。由于您在两个进程中都使用dup2
,这意味着如上所述的四个close
语句。编辑:更新了
execlp
的参数。First off, let's fix your code so that we add a tiny bit more error-checking to it, and so that it works; replace the bottom bit with:
Now, your questions:
Question: Where do I redirect it to? I know it should be one of the file descriptors, but where should it be redirected so that wc can process it?
The filedescriptors
0
,1
, and2
are special in Unix in that they are the standard input, standard output, and standard error.wc
reads from standard input, so whatever isdup
ed to0
.Question: How does wc receive the output? Through an execlp parameter? Or does the operating system check one of the file descriptors?
In general, after a process has had its image swapped out with
exec
, it will have all the open file descriptors it had beforeexec
. (Except for those descriptors with theCLOSE_ON_EXEC
flag set, but ignore that for now) Therefore, if youdup2
something to0
, thenwc
will read it.Which one of these is closed and left open for wc to receive and process ps's output?
As shown above, you can close both ends of the pipe in both child and grandchild, and that'll be fine. In fact, standard practice would recommend that you do that. However, the only truly necessary
close
line in this specific example is the one I comment as "important" - that's closing the write end of the pipe in the child.The idea is this: both child and grand-child have both ends of the pipe open when they start. Now, through
dup
we've connectedwc
to the read end of the pipe.wc
is going to keep sucking on that pipe until all descriptors on the write end of the pipe are closed, at which point it'll see that it came to the end of the file and stop. Now, in the grand-child, we can get away with not closing anything becauseps -A
isn't going to do anything with any of the descriptors but write to descriptor1
, and afterps -A
finishes spitting out stuff about some processes it'll exit, closing everything it had. In the child, we don't really need to close the read descriptor stored infd[0]
becausewc
isn't going to try to read from anything but descriptor0
. However, we do need to close the write end of the pipe in the child because otherwisewc
is just going to sit there with a pipe that's never completely closed.As you can see, the reasoning for why we didn't really need any of the
close
lines except the one marked "important" depend on the details of howwc
andps
are going to behave, so the standard practice is to close the end of a pipe you aren't using completely, and keep open the end you are using only with one descriptor. Since you're usingdup2
in both processes, that means fourclose
statements as above.EDIT: Updated the arguments to
execlp
.