linux-C/C++主子进程同时占用主进程文件描述符问题

在 Linux 系统中,当一个进程(A)打开文件并获取文件描述符(fd)后,如果通过 system() 启动子进程(B),子进程会继承父进程的所有打开文件描述符。这可能导致多个进程同时写入同一个日志文件,造成日志混乱或数据损坏。

书写辅助函数 set_fd_cloexec 为了解决这个问题。它通过设置 FD_CLOEXEC 标志位,确保在执行 exec 系列函数(如 system() 内部调用的 exec)时,文件描述符会被自动关闭,子进程不会继承该文件描述符。

函数解析

c 复制代码
static void set_fd_cloexec(int fd)
{
    if (fd < 0)  // 检查无效文件描述符
    {
        return;
    }
    int flags = fcntl(fd, F_GETFD);  // 获取当前文件描述符标志
    if (flags == -1)  // 检查获取是否失败
    {
        return;
    }
    fcntl(fd, F_SETFD, flags | FD_CLOEXEC);  // 设置 FD_CLOEXEC 标志
}

关键点说明

  1. FD_CLOEXEC 作用

    设置此标志后,当进程调用 exec 系列函数(如 system() 启动的子进程)时,操作系统会自动关闭该文件描述符,防止子进程继承。

  2. 函数逻辑

    • 先检查 fd 是否有效(fd >= 0
    • 使用 fcntl(fd, F_GETFD) 获取当前标志
    • 通过位或操作 flags | FD_CLOEXEC 添加标志
    • fcntl(fd, F_SETFD, ...) 应用新标志
  3. 使用场景

    在打开文件后立即调用此函数:

    c 复制代码
    int log_fd = open("app.log", O_WRONLY | O_CREAT | O_APPEND, 0644);
    if (log_fd >= 0) {
        set_fd_cloexec(log_fd);  // 确保子进程不继承此 fd
    }

注意事项

  1. 错误处理

    当前函数忽略了 fcntl 的失败情况,实际应用中建议添加错误日志:

    c 复制代码
    if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
        perror("fcntl(F_SETFD) failed");
    }
  2. 替代方案

    • 在打开文件时直接设置标志(更推荐):

      c 复制代码
      int fd = open("file.txt", O_RDWR | O_CLOEXEC, 0644);
    • Linux 专有函数:

      c 复制代码
      int fd = open("file.txt", O_RDWR | O_CLOEXEC, 0644);
  3. 继承例外

    若需要特定文件描述符被子进程继承(如标准输入/输出),则不应设置 FD_CLOEXEC

总结

通过正确设置 FD_CLOEXEC 标志,可确保:

  • 父进程(A)正常使用文件描述符
  • 子进程(B)启动时自动关闭该描述符
  • 避免多进程同时写文件导致的冲突
相关推荐
用户805533698036 小时前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
BadBadBad__AK18 小时前
线段树维护区间 k 次方和
c++·数学·算法·stl
AlfredZhao1 天前
生产环境里,为什么不建议把普通端口直接暴露到公网?
linux·https·443·80
卷无止境1 天前
Eigen 库如何借助 OpenMP 加速计算
c++·后端
卷无止境1 天前
OpenMPI、MPICH 与 OpenMP:关系、核心概念与架构全解
c++·后端
郝学胜_神的一滴2 天前
CMake 30:循环语法全解|foreach_while双循环精讲、迭代技巧与实战避坑指南
c++·cmake
戴为沐2 天前
Linux内存扩容指南
linux
zylyehuo3 天前
Linux 彻底且安全地删除文件
linux
用户805533698033 天前
主线 U-Boot 上 RK3506:和闭源 rkbin 拔河的三个隐性契约
linux·嵌入式
用户034095297913 天前
linux fcitx 5 雾凇拼音 设置在中文输入法下仍然输入英文标点
linux