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)启动时自动关闭该描述符
  • 避免多进程同时写文件导致的冲突
相关推荐
炸膛坦客12 小时前
单片机/C/C++八股:(二十六)IIC 专题(I²C)---- 上集
c语言·c++·单片机
旖-旎13 小时前
LeetCode 518:零钱兑换||(完全背包)—— 题解
c++·算法·leetcode·动态规划·背包问题
Henry Zhu12313 小时前
C++中的特殊成员函数与智能指针
c++
_wyt00116 小时前
多重背包问题详解
c++·背包dp
HLC++16 小时前
Linux的进程间通信
android·linux·服务器
Ljwuhe16 小时前
C++——多态
开发语言·c++
越甲八千17 小时前
STL stack为何没有迭代器
c++
华清远见IT开放实验室17 小时前
实验室建设案例 | 石家庄科技信息职业学院嵌入式实验室——从底层硬件到系统应用,一所应用型高校的嵌入式人才培养这样落地
linux·arm开发·stm32·嵌入式硬件·高校·实验室建设
从零开始的代码生活_18 小时前
C++ 继承详解:访问控制、对象模型、菱形继承与设计取舍
开发语言·c++·后端·学习·算法
云小逸18 小时前
【C++ 第七阶段:模板、泛型编程与工程综合详解】
开发语言·c++