【问题标题】:unix fork command can return only one child?unix fork 命令只能返回一个孩子?
【发布时间】:2012-10-07 08:38:53
【问题描述】:

对于这样一个菜鸟问题,我很抱歉,但我不熟悉 Unix(系统调用)。我试图理解 fork 命令,我知道如果它的子进程或者返回子 id 的 pid,fork 命令返回 pid 0。我想知道一个进程一次只能有一个子进程并返回它的 pid 还是可以有多个子进程?(实际上我无法想象如果它有多个子进程,如何返回 pid 和哪个 pid?)

【问题讨论】:

    标签: unix process fork


    【解决方案1】:

    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 可能在终端模拟器中运行)中键入命令(例如 lsdate)时,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 ProgrammingAdvanced Linux programming 书籍(后者可在线获得一些免费许可证)。

    【讨论】:

    • 看了两遍没看懂fork的用法。如果我们只有两个相同的进程副本并且一次可以使用一个,为什么我们不使用父进程来做我们想做的事情呢?为什么我们要复制相同的流程?
    • 因为fork 是创建新进程的唯一方法。 (有一些奇怪的罕见例外,但你可以先忽略它们)。在大多数 Unix 系统上,所有进程都是 pid 1 的 /sbin/init 进程的后代,并且由 fork 启动
    • 我不能在父进程中执行我想要的吗?(对不起,如果问题太基本......)
    • 是的,你可以在父进程和子进程中做你想做的事。您通常必须在分叉之前设置共享资源(如pipe(2))。您最终会更好地 wait 父母中的孩子(或者您可能会在 Joachim 的回答中提到 僵尸进程请阅读我在回答中给出的参考资料
    【解决方案2】:

    fork() 的每次调用都会创建一个子进程,并且只返回该单个进程的 PID,但没有什么能阻止您多次调用 fork() 以创建多个子进程。

    不要忘记wait() or waitpid() 让您的分叉子进程退出,否则您可能会得到zombie processes 闲逛。

    【讨论】:

    • 如果我多次调用 fork 一次又一次,为了创建新的子进程,父进程是否应该等待子进程完成?
    • @KaaN 您可以 fork() 任意数量的子进程,是的,您应该等待它们退出,否则它们会继续闲逛。你可以做阻塞或非阻塞,所以你不需要真正停止你的父进程来等待。
    • 非常感谢。如果我没有误解,我应该检查它的父进程还是子进程来创建新的。
    • @KaaN 如果 fork() 返回任何值!= 0,则您在父进程中,如果返回 0,则您在子进程中。与返回两次的单个调用有点混淆,每个进程一次 :) 父级需要等待其子级终止,子级不必知道有关其父级的任何信息。请记住检查父级中的返回值
    • 你能看看我也问过的巴兹尔回答下面的问题吗?
    【解决方案3】:

    与其他人的答案相同,但有所不同:如果每个进程只能创建一个子进程(只使用一次 fork()),那么这对进程的 lineage 意味着什么?这意味着只有一行,比如init -> login -> shell -> ls。你想要这样的系统吗?你的结论是什么?

    【讨论】:

    • 我只能想象这样简化了系统的使用……其实是不是像你的例子那样跑在后面
    • 嗯,它本质上是一个单用户、单任务系统。简单,但在当今世界并不令人满意......
    • 那么它在 x64 系统上是否会发生变化(是否相关)?还是我想的离主题太远了
    • @KaaN:我认为你很困惑。 32/64 位与什么/何时/如何分叉返回有什么关系?您可以根据需要多次 fork(),从而创建任意的兄弟树。
    • 我想是的。我应该先阅读 Basile 的参考资料。感谢您的回答感谢它:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-06
    相关资源
    最近更新 更多