【问题标题】:How does Linux determine the next PID?Linux如何确定下一个PID?
【发布时间】:2011-03-27 16:18:36
【问题描述】:

Linux 如何确定它将用于进程的下一个 PID?这个问题的目的是为了更好地理解 Linux 内核。不要害怕发布内核源代码。如果 PID 是按顺序分配的,Linux 如何填补空白?当它到达终点时会发生什么?

例如,如果我从 Apache 运行一个执行 <?php print(getmypid());?> 的 PHP 脚本,那么在点击刷新时,相同的 PID 将被打印几分钟。这段时间是 apache 接收到多少请求的函数。即使只有一个客户端,PID 最终也会改变。

当PID改变时,它会是一个接近的数字,但是如何接近呢?这个数字似乎并不完全是连续的。如果我执行ps aux | grep apache,我会得到相当多的进程:

Linux 如何选择下一个数字?之前的几个 PID 以及最近打印的 PID 仍在运行。 apache 是如何选择重用这些 PID 的?

【问题讨论】:

    标签: linux apache linux-kernel kernel


    【解决方案1】:

    我宁愿假设您观看的行为来自其他来源

    好的网络服务器通常有几个流程实例来平衡请求的负载。这些进程在一个池中进行管理,并在每次请求进入时分配给某个请求。为了优化性能,Apache 可能会将相同的进程分配给来自同一客户端的一系列顺序请求。在一定数量的请求之后,该进程被终止并创建一个新的。

    我不相信 linux 会为顺序中的多个进程分配相同的 PID。

    正如你所说,新的 PID 将接近最后一个,我猜 Linux 只是简单地为每个进程分配最后一个 PID + 1。但是有进程在后台一直弹出并被应用程序和系统终止程序,因此您无法预测接下来要启动的 apache 进程的确切数量。

    除此之外,您应该使用任何关于 PID 分配的假设作为您实施的基础。 (另见 sanmai 的评论。)

    【讨论】:

    • 我认为这部分正确,不幸的是你没有证据支持这个答案。
    • 现在我有,请参阅其他答案。 :-)
    • @Rook:如果您真的需要明确证明 PID 是按顺序分配的,请查看最新 Linux 内核树中的alloc_pidmap()
    • PID 可以随机分配。有许多扩展和补丁可以实现这一点。不要指望顺序 PID。
    【解决方案2】:

    大多数系统上的 PID are sequential。您可以通过自己在空闲机器上启动几个进程来看到这一点。

    例如使用向上箭头历史调用重复运行打印其自己的 PID 的命令:

    $ ls -l /proc/self
    lrwxrwxrwx 1 root root 0 Mar 15 19:32 /proc/self -> 21491
    $ ls -l /proc/self
    lrwxrwxrwx 1 root root 0 Mar 15 19:32 /proc/self -> 21492
    $ ls -l /proc/self
    lrwxrwxrwx 1 root root 0 Mar 15 19:32 /proc/self -> 21493
    $ ls -l /proc/self
    lrwxrwxrwx 1 root root 0 Mar 15 19:32 /proc/self -> 21494
    

    不要依赖于此:出于安全原因,有些人运行的内核会花费额外的 CPU 时间来随机选择新的 PID。

    【讨论】:

    • 这似乎不是真的。
    • @chiccodoro 截图发布。
    • @The Rook 它只是这样出现。如果你有进程 1234 ,也许下一个进程 you create 得到 1245。这意味着同时启动了一些其他进程(并且因为死亡) - 例如创建了一个新的 mysql 线程,运行了一些系统/cron/任何进程,一些 php 页面运行了 10 个外部命令等。您的屏幕截图仅说明在 apache 启动某些进程之间,系统启动了其他进程,或者您正在运行apache 在多线程模式下,让一些线程获得“缺失”的 id。 pid 分配是系统范围的。
    • @The Rook:您应该查看我的回答,它解释了为什么您的数字不连续
    【解决方案3】:

    PID 可以随机分配。有a number of ways 来实现这一点。

    【讨论】:

    • 据我所知,PID 随机化被 Linux 内核开发团队拒绝,因为它的安全性是通过默默无闻的。
    【解决方案4】:

    内核在 (RESERVED_PIDS, PID_MAX_DEFAULT) 范围内分配 PID。它在每个命名空间中按顺序执行(不同命名空间中的任务可以具有相同的 ID)。如果范围用完,则 pid 分配回绕。

    一些相关代码:

    alloc_pid(...) 内部

    for (i = ns->level; i >= 0; i--) {
        nr = alloc_pidmap(tmp);
        if (nr < 0)
            goto out_free;
        pid->numbers[i].nr = nr;
        pid->numbers[i].ns = tmp;
        tmp = tmp->parent;
    }
    

    alloc_pidmap()

    static int alloc_pidmap(struct pid_namespace *pid_ns)
    {
            int i, offset, max_scan, pid, last = pid_ns->last_pid;
            struct pidmap *map;
    
            pid = last + 1;
            if (pid >= pid_max)
                    pid = RESERVED_PIDS;
            /* and later on... */
            pid_ns->last_pid = pid;
            return pid;
    }
    

    请注意,内核上下文中的 PID 不仅仅是int 标识符;相关结构见/include/linux/pid.h。除了 id 之外,它还包含具有该 id 的任务列表、引用计数器和用于快速访问的散列列表节点。

    PID 在用户空间中不连续出现的原因是内核调度可能会在您的进程的fork() 调用之间分叉一个进程。事实上,这很常见。

    【讨论】:

    • 有什么方法可以映射全局和命名空间 PID 的吗?
    • @SowndaryaK 是的,请参见 /proc//status 文件,它包含 在全局和 PIDs 命名空间中的映射。看看NSpid这个字段,它会告诉你这个进程在不同的PID命名空间中分配了什么PID。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-25
    • 1970-01-01
    • 2011-08-26
    • 2012-10-13
    • 2012-06-05
    • 2012-04-29
    相关资源
    最近更新 更多