【问题标题】:I can't run more than 100 processes我不能运行超过 100 个进程
【发布时间】:2010-11-22 00:13:10
【问题描述】:

我有大量的 shell 命令通过授权服务的“AuthorizationExecuteWithPrivileges”调用以 root/admin 权限执行。问题是在一段时间后(10-15 秒,可能是 100 个 shell 命令)程序停止响应,并在调试器中出现此错误:

无法分叉:errno 35

然后,当应用程序运行时,我无法启动更多应用程序。我研究了这个问题,显然这意味着系统没有更多线程可供使用。但是,我使用 Activity Monitor 进行了检查,发现我的应用只使用了 4-5 个线程。

为了解决这个问题,我认为我需要做的是将 shell 命令分离到一个单独的线程中(远离主线程)。我以前从未使用过线程,我不确定从哪里开始(我找不到全面的示例)

谢谢

【问题讨论】:

    标签: macos process authorizationservices


    【解决方案1】:

    这与线程无关(至少不是您应用程序中的线程)。这是关于系统资源的。这些分叉进程中的每一个都消耗至少 1 个内核线程(可能更多)、一些 vnode 和许多其他东西。最终系统将不允许您生成更多进程。

    您遇到的第一个限制是管理限制。系统可以支持更多,但可能会导致性能下降和其他问题。您通常可以通过各种机制(如 sysctls)来提高这些。一般来说,这样做是个坏主意,除非您有特定的(特殊)工作负载,并且您知道会从特定的调整中受益。

    提高这些限制可能无法解决您的问题。虽然调整这些限制可能会使您运行更长时间,但为了实际修复它,您需要弄清楚为什么资源没有返回到系统。根据您上面描述的内容,我猜您的分叉进程永远不会退出。

    【讨论】:

    • IIRC,您还必须确保有人正在呼叫wait(2)init 进程最终会等待它们,但是如果每个子进程的运行时间很短,则可能会在此期间耗尽资源。
    • 这是真的,通常你需要调用 wait() 或 witpid() 除非进程以某种方式分离自己。
    • hmm 你能详细说明在这种情况下如何使用 wait() 吗?谢谢
    • 您只需调用 wait() (在父级中)并且二进制文件在那里等待直到子级完成,然后等待返回。您应该为每个分叉调用一次等待,但您可以执行多个分叉,然后根据需要进行多次等待。您还可以使用 waitpid() 来等待特定的孩子。
    【解决方案2】:

    正如 Louis Gerbarg 已经指出的那样,您的问题与线程无关。我已经相应地编辑了你的标题和标签。

    我有大量的 shell 命令正在通过授权服务的“AuthorizationExecuteWithPrivileges”调用以 root/admin 权限执行。

    不要那样做。该功能仅存在,因此您可以将 root:admin 所有权和 setuid 模式位恢复到您要以 root 身份运行的工具。

    这个想法是你应该将应该以root身份运行的代码与不需要以root身份运行的部分完全分开,以便需要root的部分可以拥有它(通过setuid位) 并且不需要 root 的部分可以没有它(通过没有 setuid)。

    Authorization Services Programming Guide 中有一个代码示例。

    问题是在一段时间后(10-15 秒,可能是 100 个 shell 命令),程序在调试器中停止响应并出现此错误:

    couldn't fork: errno 35
    

    是的。您一次只能运行几百个进程。这是操作系统强制的限制。

    这是一个软限制,这意味着你可以提高它——但只能达到硬限制,你不能提高它。查看limitlimit -h 的输出(在zsh 中;我不知道其他shell)。

    在运行更多进程之前,您需要等待进程完成。

    然后,当应用程序运行时,我无法启动更多应用程序。

    因为您已经在运行尽可能多的进程。 x-hundred-process 限制是每个用户,而不是每个进程。

    我研究了这个问题,显然这意味着系统没有更多线程可供使用。

    不,它没有。

    errno 错误代码用于许多事情。 EAGAIN(35,“资源暂时不可用”)可能意味着当由启动线程的系统调用设置时不再有线程,但这并不意味着当由另一个系统调用或函数设置时。

    您引用的错误消息明确表示它是由fork 设置的,这是启动新进程而不是新线程的系统调用。在这种情况下,EAGAIN 的意思是“你已经在运行尽可能多的进程”。见the fork manpage

    但是,我使用 Activity Monitor 进行了检查,发现我的应用只使用了 4-5 个线程。

    看到了吗?

    为了解决这个问题,我认为我需要做的是将shell命令分离到一个单独的线程中(远离主线程)。

    每个线程启动一个进程只会帮助您更快地用完进程。

    我以前从未使用过线程……

    听起来你还没有,因为你所指的函数启动了一个进程,而不是一个线程。

    【讨论】:

    • 感谢您的回答 :) 我想我应该创建一个新的 CLI 工具或脚本来运行这些命令,然后让应用程序以管理员权限执行该工具。这行得通吗?
    • 这只是一个很好的解决方案,只要您不使其能够以 root 身份运行 any 进程。那将是一个巨大的安全漏洞。为每个任务制作一个工具,或者,如果您的工具运行系统上安装的另一个工具,则让您的工具只接受白名单中的选择。
    • 此外,如果您的工具确实运行安装在系统上的工具,请确保将 PATH 限制在可能的位置。硬编码路径(例如 /bin/ls)可能会更好。不允许攻击者使用 PATH 以假名运行他们选择的代码。
    • 是的,我将使用硬编码路径。另外,还有一件事。我正在使用进度条来指示已复制了多少文件。使用单独的工具,有什么方法我仍然可以看到列表中有多少文件已被复制(就像实时提要一样),以便我可以相应地更新我的进度条?我想我可以让它像“1”和“2”这样的数字记录到日志文件中,然后让应用程序定期检查日志以查看已复制的内容,但有更好的方法吗?谢谢
    • 这与这个问题无关。您应该将其作为一个新问题提出。
    猜你喜欢
    • 2021-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多