You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux环境C语言如何不打开文件检测是否被其他进程占用

Linux下无打开操作检测文件占用状态的实现方案

Linux默认没有提供专门的系统调用,用来在不打开目标文件的前提下检测文件是否被其他进程以读/写模式占用,但可以通过内核暴露的procfs接口实现完全无侵入的检测,结合文件锁机制可以直接满足互斥打开的需求。

核心原理

  • Linux内核默认允许多个进程同时以读写模式打开同一个文件,原有代码里两个进程同时执行fopen("distributed.txt", "r+")都会拿到有效文件指针,不会出现返回NULL的情况,这是VFS层的默认设计。
  • 全程不打开目标文件的检测逻辑可以完全基于procfs实现:
    • 第一步调用stat()读取目标文件的元数据,获取文件所在设备号、inode号,这个操作不会触发文件打开动作,仅读取文件系统的元数据信息。
    • 两种检测路径可选:
      • 检测文件是否被加锁:直接读取/proc/locks文件,遍历所有内核记录的锁条目,匹配对应设备号和inode号即可判断是否有进程持有该文件的锁,全程不需要触碰目标文件。
      • 检测任意进程的打开动作:遍历/proc下所有进程ID命名的目录,读取每个进程的/proc/<pid>/fd下的文件描述符符号链接,对比链接目标的设备号、inode号和目标文件是否一致,还可以读取/proc/<pid>/fdinfo/<fd>的flag字段,判断该文件描述符的打开模式是读、写还是读写。这个方法同样不需要打开目标文件,仅需要对应进程fd目录的读取权限(普通用户只能读取自身进程的fd信息,root可读取所有进程的)。

需求适配实现

要实现「第一个进程持有文件时,第二个进程不尝试打开文件直接返回NULL,等文件释放后再拿到有效指针」的效果,最稳定的方案是劝告式排他锁+procfs锁检测,比遍历所有进程fd的性能开销低很多,也不存在轮询的资源浪费。
修正后的可运行代码如下:

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/sysmacros.h>

// 给文件加整个文件范围的排他写锁
int lock_file(int fd) {
    struct flock fl;
    memset(&fl, 0, sizeof(fl));
    fl.l_type = F_WRLCK;
    fl.l_whence = SEEK_SET;
    fl.l_start = 0;
    fl.l_len = 0;
    return fcntl(fd, F_SETLK, &fl);
}

// 不打开目标文件,直接通过/proc/locks检测是否有进程持有文件锁
int is_file_locked(const char *filepath) {
    struct stat st;
    if (stat(filepath, &st) == -1) {
        return -1;
    }
    FILE *locks_fp = fopen("/proc/locks", "r");
    if (!locks_fp) return -1;
    char line[256];
    while (fgets(line, sizeof(line), locks_fp)) {
        long long inode;
        unsigned int major, minor;
        if (sscanf(line, "%*d %*s %*c %*d %x:%x:%lld", &major, &minor, &inode) == 3) {
            if (major == major(st.st_dev) && minor == minor(st.st_dev) && inode == st.st_ino) {
                fclose(locks_fp);
                return 1;
            }
        }
    }
    fclose(locks_fp);
    return 0;
}

int main() {
    FILE *demo;
    const char *filepath = "distributed.txt";

    if (getenv("FIRST_TIME")) {
        demo = fopen(filepath, "r+");
        if (!demo) {
            perror("first process fopen failed");
            return 1;
        }
        if (lock_file(fileno(demo)) == -1) {
            perror("first process lock failed");
            fclose(demo);
            return 1;
        }
        printf("first process hold file for 15s\n");
        sleep(15);
        fclose(demo);
    } else {
        // 不打开文件,先检测锁状态
        if (is_file_locked(filepath)) {
            printf("file is occupied by other process, demo is NULL\n");
            demo = NULL;
        } else {
            demo = fopen(filepath, "r+");
            // 二次加锁检查避免竞争条件
            if (demo && lock_file(fileno(demo)) == -1) {
                fclose(demo);
                demo = NULL;
                printf("file lock race, demo is NULL\n");
            } else {
                printf("demo is %p \n", demo);
                fclose(demo);
            }
        }
    }
    return 0;
}

注意事项

  • 上述检测逻辑全程没有执行目标文件的open/fopen操作,完全符合不主动尝试打开文件的要求。
  • 劝告锁需要所有访问该文件的进程都主动遵守加锁规则才能生效,如果需要内核强制拦截未持锁进程的打开操作,可以给文件设置强制锁属性,对应分区挂载时开启mand参数即可。
  • 如果需要等待文件释放而不是直接返回NULL,可以搭配inotify机制监听目标文件的关闭事件,不需要轮询检测锁状态。

内容的提问来源于stack exchange,提问作者Gourish Singla

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 03:12:15