【问题标题】:fork+exec without atfork handlers没有 atfork 处理程序的 fork+exec
【发布时间】:2018-03-30 08:27:33
【问题描述】:

我有一个库,它注册了一个atfork 处理程序(通过pthread_atfork()),它在调用fork() 时不支持多线程。就我而言,我不需要分叉环境可用,因为我只想在fork() 之后立即调用exec()。所以,我想要 fork() 但没有任何 atfork 处理程序。那可能吗?我会错过任何重要的边缘案例吗?

关于背景信息,库是 OpenBlas,问题描述为 herehere

【问题讨论】:

  • 如果 OpenBlas 注册了一个 通常 在多线程程序中不能可靠工作的 atfork 处理程序,那么 OpenBlas 在这方面存在缺陷。 pthread_atfork() 没有其他预期的用例。如果这确实是 OpenBlas 的问题,并且您不准备自己修复它或等待维护人员修复它,那么您最好的选择可能是选择不同的 BLAS 库。

标签: c linux fork exec posix


【解决方案1】:

您可以使用vfork()(NPTL 实现不调用 fork 处理程序)。尽管 POSIX 已从标准中删除了 vfork,但它很可能在您的实现中可用。

使用 pthread_atfork(3) 建立的 Fork 处理程序在以下情况下不会被调用 使用 NPTL 线程库调用的多线程程序 叉子()。在这种情况下,在使用的程序中调用分叉处理程序 LinuxThreads 线程库。 (参见 pthreads(7) Linux 线程库的描述。)

或者,posix_spawn()。这类似于vfork。手册页说:

根据 POSIX,它未指定在调用 posix_spawn() 时是否调用使用 pthread_atfork(3) 建立的分叉处理程序。在 glibc 上,只有在子进程是使用 fork(2) 创建时才会调用 fork 处理程序。

或者,syscall,直接使用SYS_cloneSYS_clone 是用于在 Linux 上创建线程和进程的系统调用号。所以syscall(SYS_clone, SIGCHLD, 0); 应该可以工作,前提是你会立即执行。

syscall(SYS_fork);(由 Shachar 回答)也可能会起作用。但请注意,SYS_fork 在某些平台上不可用(例如,aarch64、ia64)。 SYS_fork 在 Linux 中被认为是过时的,它只是为了向后兼容而存在,Linux 内核使用 SYS_clone 来创建所有“类型”的进程。

(注意:这些选项大多仅限于 glibc/Linux)。

【讨论】:

    【解决方案2】:

    是的。以下内容应该适用于 Linux(并且,我认为,所有基于 glibc 的平台):

    #define _GNU_SOURCE
    #include <unistd.h>
    #include <sys/syscall.h>
    
    ...
      syscall(SYS_fork);
    

    这会绕过库并直接调用fork 的系统调用。如果您的平台没有将fork 实现为单个系统调用,您可能会遇到麻烦。对于 Linux,这仅仅意味着您应该改用 clone

    考虑到这一点,我不确定我是否会推荐这样做。由于您是图书馆,您不知道为什么有人注册了atfork。假设它无关紧要是不好的编程习惯。

    所以你为了做一些可能会或可能不会破坏东西的事情而失去了可移植性,所有这些都是以什么名义?保存几个函数调用?就个人而言,我只会使用fork

    【讨论】:

    • 请注意,如果您在实现中可以使用此方法,则可以替代直接调用 fork()。它没有解决间接调用fork()的情况,例如通过system()popen()
    • 我想没有办法让代码更加独立于平台,例如对于 MacOSX,我需要其他代码吗?另一个问题:如果我打算在fork() 之后立即调用exec(),那么运行任何atfork-handlers 的可能原因是什么?
    • @Albert 但是您的 C 库的 fork 不知道您将立即执行 ;-) 即使它知道,它仍然不能跳过 fork 处理程序,因为它需要按文档运行它们。如果您正在寻找便携性,也许posix_spawn 是您的最佳选择。
    • @usr:它当然不知道。但是例如vfork() 似乎这样做了,就像 fork() 但没有调用 atfork 处理程序。我的问题是,当我想在之后调用exec() 时,是否有任何情况下我会调用 atfork 处理程序。
    • pthread_atfork 的最常见用例是在 fork 后的子进程中保持多线程程序中的资源(互斥体、条件变量等)处于一致状态。如果您立即执行,则无需担心任何此类不一致 - 您已将其完全替换为新的过程映像。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-01
    • 1970-01-01
    • 2014-06-09
    • 2015-12-01
    • 2011-10-08
    • 2011-10-06
    相关资源
    最近更新 更多