父进程将创建管道,如果父进程进行分叉,子进程将继承该管道。现在我们拥有了与子进程的直接链接,它们可以通信?
当我们开始关闭管道和重定向管道时,我感到困惑。有没有人能够对关闭管道和重定向管道给出一个很好的解释?
提前致谢。
以下是内容翻译:
以下是示意图:
P1=[WR FD]===========[RD FD]=[STDIN]=P2
P1=[RD FD]===========[WR FD]=[STDOUT]=P2
P1 and P2 are processes. And "===" depict the pipes.
你的问题涉及关闭和重定向。这在你执行我之前提到的转换时发挥作用。假设你已经使用pipe()系统调用获得了一个管道。
int fd[2];
pipe(fd);
if (!fork()) // 0 return value indicates that you are in the child process
{
dup2(fd[0], 0); // dup2 first closes 0 in the child process, then duplicates
// fd[0] as 0; keep in mind that 0 is stdin and fd[0] is the
// read end of the pipe
exec(something); // start the new process, which when it reads stdin, will be
// reading the pipe instead
}
请参见管道。
Simple example
ls -l | less
In this example, ls is the Unix directory lister, and less is an interactive text pager with searching capabilities. The pipeline lets the user scroll up and down a directory listing that may not fit on the screen.
Creating pipelines programmatically
Pipelines can be created under program control. The Unix
pipe()
system call asks the operating system to construct a new anonymous pipe object. This results in two new, opened file descriptors in the process: the read-only end of the pipe, and the write-only end. The pipe ends appear to be normal, anonymous file descriptors, except that they have no ability to seek.To avoid deadlock and exploit parallelism, the Unix process with one or more new pipes will then, generally, call
fork()
to create new processes. Each process will then close the end(s) of the pipe that it will not be using before producing or consuming any data.
dup
系统调用系列将新的文件描述符更改为前三个系统调用之一。int new_stdout = open("filename", O_WRONLY);
/* ... error check ... */
if (!fork()) {
/* in child */
dup2(new_stdout, 1);
execve("program", argv, envp);
我们经常使用管道。正如Amardeep所说,子进程继承了父进程的描述符,包括管道。
这里是两个命令的示例。我不确定对于n个命令的算法是否正确 :-)
void do__pipe(char** cmd1, char** cmd2)
{
int fd[2]; /* fd[0] for reading fd[1] for writting */
if (pipe(fd) == -1)
{
perror("pipe");
}
switch (fork())
{
case -1:
perror("fork"); exit (1);
case 0:
close (fd[0]);
dup2 (fd[1], STDOUT_FILENO);
close (fd[1]);
execvp (cmd1[0], cmd1);
exit (1);
}
dup2(STDIN_FILENO, STDIN_FILENO);
switch (fork())
{
case -1:
perror("fork (2)"); exit (1);
case 0:
close (fd[1]);
dup2 (fd[0], STDIN_FILENO);
close (fd[0]);
execvp (cmd2[0], cmd2);
exit (1);
}u
wait((int*)NULL);
}
这段代码是我为了我的学业而编写的一个小型shell程序中提取出来的,所以char ** cmd1应该类似于["cat", "/etc/passwd"],而cmd2可能是["wc", "-l"]
子进程继承了父进程的打开描述符。默认的描述符是stdin、stdout和stderr。它们不能提供子进程直接与父进程通信的方式,因为它们实际上是到控制台的。所以通常你会关闭或重定向它们,这样就不会污染父进程的控制台I/O。
但是如果你有一对打开的管道,你可以使用它们的描述符作为子进程继承的方式在两个进程之间进行双向通信。每个方向使用一个描述符。