【问题标题】:How does shell pipe the child process? [duplicate]shell如何管道子进程? [复制]
【发布时间】:2013-12-15 18:12:38
【问题描述】:

最近在研究linux进程间通信。但是我在理解管道机制方面存在一些问题。

我知道管道是父进程创建的一对文件,然后父进程将文件描述符传递给其子进程,然后子进程可以对其进行操作。

但是既然子进程在fork()之后调用exec()时拥有了一个全新的虚拟内存,那么为什么父进程可以将它的信息传递给子进程呢?我有什么遗漏的吗?

【问题讨论】:

  • 文件描述符指向内核中通用的文件数据结构,因此内核可以将同一个文件暴露给多个进程。
  • 查看 www.aosabook.org (bash) 和 Jessi Storimer (jstorimer.com/blogs/workingwithcode/…)。不知道这是否会回答你的问题,但会给你一些见解。

标签: c++ c linux unix linux-kernel


【解决方案1】:

文件描述符是操作系统(内核)管理的资源的句柄。当您创建管道时,内核会创建设施,以便数据可以从管道的一端发送到另一端。

这些数据是通过内核发送的。

当你 fork() 时,子进程继承了所有文件描述符,这意味着它们继承了文件描述符所引用的内核管理的数据结构。 所以现在文件描述符指的是子级和父级中完全相同的内核资源。由于内核资源存在于内核中,该部分在 2 个进程之间共享,它不像用户空间内存那样重复。

基本上,您将 write() 数据写入管道的一端,该数据被复制到内核中的缓冲区中。然后,您可以 read() 该数据,并将其从内核缓冲区复制到读取过程的内存空间中。在 fork() 之后,child 和 parent 都引用内核中使用 pipe() 创建的同一个缓冲区。

【讨论】:

  • 由内核管理的资源称为文件描述。来自openopen() 函数应在文件和文件描述符 之间建立连接。它应创建一个引用文件的打开文件描述和引用该打开文件描述文件描述符。其他 I/O 函数使用文件描述符来引用该文件。
【解决方案2】:

当一个进程执行() 到另一个进程时,该子进程通常会继承父进程的标准文件路径:stdin(0)、stdout(1)、stderr(2)。当 shell 创建管道时,它使用 dup2() 调用将路径复制到所需的路径编号,以强制将正确的路径指向子标准路径。

// pseudo-code:
// create the pipe
int pipe_end[2];
pipe(pipe_end);

// "back up" stdin
int save_in = dup(0);

// position the pipe to stdin for the benefit of the child
dup2(pipe_end[0], 0);

// start the child
fork() && exec();

// restore stdin
close(0);
dup2(save_in, 0);

// write to the child
write(pipe_end[1], ...);

【讨论】:

    【解决方案3】:

    信息不会传递给子进程 - 它是通过隐式约定完成的。父级知道它应该将 fds 复制到插槽 0、1、2 中,而子级知道从这些描述符中读取/写入。你是对的,整个 exec 没有任何魔法,除了参数和环境向量之外,孩子确实从其父母那里获得了零信息。只是unix平台有这些约定,所以孩子知道它要使用的相关fds,而父母知道为fds选择哪些数字。

    对于需要传递两个或三个以上 fd 的进程,父进程确实必须显式传递数字。以下是我机器上明显发生的一些进程(它可能填充在其他地方的环境变量中):

    • klauncher --fd=8
    • /bin/dbus-daemon --fork --print-pid 5 --print-address 7 --session

    【讨论】:

      猜你喜欢
      • 2023-03-07
      • 2017-02-18
      • 2012-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-11
      • 1970-01-01
      • 2018-08-04
      相关资源
      最近更新 更多