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)启动时自动关闭该描述符
  • 避免多进程同时写文件导致的冲突
相关推荐
我头发多我先学14 小时前
C++ 模板全解:从泛型编程初阶到特化、分离编译进阶
java·开发语言·c++
爱编码的小八嘎14 小时前
C语言完美演绎8-15
c语言
YSF2017_314 小时前
C语言16-makefile(3)——makefile的模式规则
linux·c语言·开发语言
星星码️14 小时前
C++选择题练习(一)
开发语言·c++
不做无法实现的梦~15 小时前
Linux 上使用 CLion 开发嵌入式,并用 Codex CLI
linux·运维·服务器
张32316 小时前
Ansible拆分大型Playbook
linux·ansible
dgaf16 小时前
谢谢 AI (打靶测试用文)
c语言·gpt·ai编程·d3d12
苦逼大学生被编程薄纱17 小时前
Ext 文件系统基础:Linux 存储基石入门(下)
linux·运维·服务器
Lumos_77717 小时前
Linux -- 进程
linux·运维·服务器
小苗卷不动17 小时前
OJ练习之疯狂的自我检索者(简单)
c++