【发布时间】:2012-10-07 08:38:53
【问题描述】:
对于这样一个菜鸟问题,我很抱歉,但我不熟悉 Unix(系统调用)。我试图理解 fork 命令,我知道如果它的子进程或者返回子 id 的 pid,fork 命令返回 pid 0。我想知道一个进程一次只能有一个子进程并返回它的 pid 还是可以有多个子进程?(实际上我无法想象如果它有多个子进程,如何返回 pid 和哪个 pid?)
【问题讨论】:
对于这样一个菜鸟问题,我很抱歉,但我不熟悉 Unix(系统调用)。我试图理解 fork 命令,我知道如果它的子进程或者返回子 id 的 pid,fork 命令返回 pid 0。我想知道一个进程一次只能有一个子进程并返回它的 pid 还是可以有多个子进程?(实际上我无法想象如果它有多个子进程,如何返回 pid 和哪个 pid?)
【问题讨论】:
Fork 不是 Unix 命令,而是在 fork(2) Posix 手册页中记录的 syscall。 Linux 手册页是 fork(2) -linux- 这里。
成功时,fork 系统调用返回两次:一次在(调用)父进程中(它给出子进程的pid),一次在新创建的子进程中(它给出 0) .否则,这两个进程是克隆的(一些 Linux 实现在 Linux 特定的clone(2) 系统调用之上实现了一个fork)并且正在执行具有几乎相同状态的相同程序(实际上是两个几乎相同的副本)。两个(父子)进程同时运行(作为内核调度的任务,可能在不同的处理器内核上并行运行)。
fork(2) 系统调用可能(很少)失败(例如,为了避免 fork bombs),例如当达到setrlimit(2) 系统调用设置的RLIMIT_NPROC 限制时。当它失败时,fork 系统调用返回 -1,你应该检查errno。检查每个系统调用的失败是一个好习惯,fork 也不例外。
Fork 是启动进程的常用方法,所有 [除了一些罕见的例外] 用户进程都是由一些 fork 系统调用(或类似 vfork(2) 或 clone(2) 的变体)启动的。特别是,当您在 shell(例如 /bin/bash 可能在终端模拟器中运行)中键入命令(例如 ls 或 date)时,shell 通常是 fork-ing 本身,然后是 execve -ing 所需的程序(例外是像cd 这样的shell 内置程序)。
请注意,Linux 系统上的几乎所有进程都是由fork 创建的。例外是内核启动的进程,如 /sbin/init 或 /sbin/modprobe ...
您可以多次调用fork(典型的shell 实现对每个命令都执行此操作,除了像cd 这样的内置命令;您可能想研究像sash 或@987654357 这样的免费软件shell 的源代码@)。您最终应该使用wait(2) 或waitpid(2) 系统调用等待子进程。进程可以使用execve(2) 系统调用更改其可执行文件和地址空间。它的address space 可以使用mmap(2) 和相关的系统调用进行更改。
您可能想使用strace -f 来了解进行了哪些系统调用,例如通过一些外壳。
我强烈建议阅读Advanced Unix Programming 和Advanced Linux programming 书籍(后者可在线获得一些免费许可证)。
【讨论】:
fork 是创建新进程的唯一方法。 (有一些奇怪的罕见例外,但你可以先忽略它们)。在大多数 Unix 系统上,所有进程都是 pid 1 的 /sbin/init 进程的后代,并且由 fork 启动
pipe(2))。您最终会更好地 wait 父母中的孩子(或者您可能会在 Joachim 的回答中提到 僵尸进程。请阅读我在回答中给出的参考资料。
对fork() 的每次调用都会创建一个子进程,并且只返回该单个进程的 PID,但没有什么能阻止您多次调用 fork() 以创建多个子进程。
不要忘记wait() or waitpid() 让您的分叉子进程退出,否则您可能会得到zombie processes 闲逛。
【讨论】:
与其他人的答案相同,但有所不同:如果每个进程只能创建一个子进程(只使用一次 fork()),那么这对进程的 lineage 意味着什么?这意味着只有一行,比如init -> login -> shell -> ls。你想要这样的系统吗?你的结论是什么?
【讨论】: