当前位置: 首页 > 面试题库 >

调用posix_spawn时关闭所有文件句柄

王高邈
2023-03-14
问题内容

我想使用posix_spawn(…)(或非常相似的东西)生成一个进程集合。此函数接受posix_spawn_file_actions_t类型的参数,该参数允许我指定应如何对待打开的文件句柄。从文档中可以确定,所有文件都是从调用进程继承的,并根据posix_spawn_file_actions_t结构中的信息进行了修改。

我希望所有文件都不会被生成的进程打开(stdin,stdout和stderr除外)。有谁知道如何做到这一点?显然,这可以在某些实现中使用’POSIX_SPAWN_CLOEXEC_DEFAULT’派生属性标志来完成,但这在我的平台上不可用。每当我打开文件时,我也可以使用fcntl(…)指定“在exec上关闭”,但我认为更可本地化解决此问题的方法是可取的。


问题答案:

使用文件租约和/或锁(记录锁)在多线程应用程序中fork()以及exec*()在多线程应用程序中打开文件描述符处理fcntl()是很容易的。

通常,O_CLOEXEC/
fcntl(fd, F_SETFD, FD_CLOEXEC)选项比显式关闭描述符更可取,因为显式关闭描述符有一些不良的副作用。特别是,如果您对描述符有租约,则在子进程中关闭描述符将释放租约。

请注意,在Linux中,fcntl()锁不会跨fork(); 继承。参见man 2
fork中的
描述。

posix_spawn()是在C库中实现的,文件操作可以由posix_spawn_file_actions_init()posix_spawn_file_actions_addclose()等管理。查看手册页中的
另请参阅 列表。就我个人而言,我不会使用此接口,因为在子进程之前关闭描述符exec*()至少很简单。

由于上述所有原因,我个人更喜欢使用O_CLOEXEC和/或使用打开文件,fcntl(fd,F_SETFD,FD_CLOEXEC)以便默认情况下所有描述符都在执行时关闭。就像是

#define _GNU_SOURCE
#define _POSIX_C_SOURCE 200809L
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/resource.h>

void set_all_close_on_exec(void)
{
    struct rlimit  rlim;
    long           max;
    int            fd;

    /* Resource limit? */
#if defined(RLIMIT_NOFILE)
    if (getrlimit(RLIMIT_NOFILE, &rlim) != 0)
        rlim.rlim_max = 0;
#elif defined(RLIMIT_OFILE)
    if (getrlimit(RLIMIT_OFILE, &rlim) != 0)
        rlim.rlim_max = 0;
#else
    /* POSIX: 8 message queues, 20 files, 8 streams */
    rlim.rlim_max = 36;
#endif

    /* Configured limit? */
#if defined(_SC_OPEN_MAX)
    max = sysconf(_SC_OPEN_MAX);
#else
    max = 36L;
#endif

    /* Use the bigger of the two. */
    if ((int)max > (int)rlim.rlim_max)
        fd = max;
    else
        fd = rlim.rlim_max;

    while (fd-->0)
        if (fd != STDIN_FILENO  &&
            fd != STDOUT_FILENO &&
            fd != STDERR_FILENO)
            fcntl(fd, F_SETFD, FD_CLOEXEC);
}

这是一种可移植的方法,用于快速将所有打开的描述符(标准描述符除外)设置为执行时关闭;库有时在内部使用描述符,而未设置O_CLOEXEC。在我的系统上,set_all_close_on_exec()需要0.25ms才能运行;最大值分别为4096和1024,因此最终尝试设置4093文件描述符。

(请注意,fcntl(fd,F_SETFD,FD_CLOEXEC)对于所有有效的描述符应该成功,而errno==EBADF对于其他(无效/未使用的)描述符则失败。)

请注意,仅尝试在所有可能的描述符上设置标志比尝试找出实际打开的描述符要快得多。(后者可以在Linux中通过例如)/proc/self/fd/

其次,我更喜欢使用一个辅助函数来创建到子进程的控制管道,将文件描述符移动到它们适当的位置(并不总是很琐碎),然后分叉子进程。签名通常类似于

int do_exec(pid_t *const childptr,
            const char *const cmd,
            const char *const args[],
            const int stdin_fd,
            const int stdout_fd,
            const int stderr_fd);

我的do_exec()函数创建了一个执行时关闭控制管道,以区分执行子二进制文件的失败状态和子二进制文件退出状态。(如果子进程失败exec(),它将errno作为签名的char
写入控制管道。父进程尝试从控制管道的另一端读取单个签名的char。如果成功,则exec失败;父进程收获子进程使用例如waitpid(),并返回errno错误。否则,由于exec()导致管道已关闭,因此父进程知道子进程已开始执行,并可以关闭(控制管道的最后打开端)。

最后,如果您有一个多线程服务器类型的进程需要以最小的延迟和最少的资源生成新的子进程,请使用Unix域套接字启动连接到原始进程的单个子进程(因为您可以使用辅助消息来传输凭据)和使用这些描述符的文件描述符),并让该子进程开始实际的子进程。这正是Apache
mod_cgid和大多数FastCGI实现所要做的。



 类似资料:
  • 问题内容: 我正在使用JAI读取Java中的Tiff文件。使用此代码: 在使用Java 7的一个盒子上工作正常,但在使用Java 8的其他盒子上工作正常,请执行以下操作: 问题答案: 我的理论是,垃圾回收正在启动并完成一些本不该垃圾回收的工作。很奇怪。替换为: 问题似乎消失了。我的猜测是因为不会过早收集,因为它的句柄仍在局部变量范围内。可能还有其他JAI方法也可以做到这一点,只要确保在输入流上保留

  • 函数名称:关闭文件句柄 函数功能:关闭文件句柄 函数方法 io.close() 函数用例 file,msg = io.open("/mnt/sdcard/kazhu.txt") if file then dialog("打开成功",5000) file:close() else dialog("打开失败,失败原因:"..msg,5000) end

  • 问题内容: 我有两个goroutines独立产生数据,每个将它们发送到一个通道。在我的主要goroutine中,我想在输入这些输出时使用它们,但是不在乎它们的输入顺序。每个通道在耗尽其输出时都会自行关闭。虽然select语句是用于像这样独立使用输入的最佳语法,但是直到两个通道都关闭之前,我还没有看到一种简洁的循环方法。 我能想到的最好的方法是以下操作(只是草绘,可能会有编译错误): 但是,如果您使

  • 我在一个文件夹里有svg图标,我想通过它们来循环。如何使用JS实现这一点? SVG图标-常规是我的文件夹路径。 HTML文件

  • 我正试图遵循中给出的例子https://developers.itextpdf.com/examples/page-events/clone-page-events-headers-and-footers#2656-可变标题。java创建带有可变标题的PDF文档。但这些事件并没有被正确地触发。下面是我测试过的代码- 如果我运行这个代码,所有页面都显示标题为“3的因素”。但是他们应该在第一页显示“2

  • 问题内容: 我正在制作网络爬虫。我将网址传递给搜寻器函数,并对其进行解析以获取锚标记中的所有链接,然后为所有这些网址使用相同的搜寻器函数,并对每个网址使用单独的goroutine。 但是,如果在我收到响应之前发送请求并取消它,则该特定请求的所有程序仍在运行。 现在我想要的是,当我取消请求时,由于该请求而被调用的所有goroutine都会停止。 请指导。 以下是我的 搜寻器 功能代码。 以下是我的P