shell如何管理子进程?

时间:2013-11-29 14:08:10

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

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

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

但是,当在fork()之后调用exec()时,子进程有一个全新的虚拟内存,那么为什么父进程可以将其信息传递给子进程?有什么我错过了吗?

3 个答案:

答案 0 :(得分:2)

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

此数据通过内核发送。

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

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

答案 1 :(得分:2)

当进程exec()s到另一个进程时,该子进程通常继承父进程的标准文件路径: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], ...);

答案 2 :(得分:0)

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

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

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