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

进程持有flock文件排他锁时其他进程写入行为解析

flock锁行为说明与代码问题排查

核心机制结论

  • 默认配置下flock实现的是建议性文件锁,内核不会主动拦截未调用flock的进程的读写操作。也就是说,某进程持有排他锁时,其他进程直接调用write写入文件会直接执行成功,既不会阻塞也不会返回失败——锁的互斥逻辑只对主动调用flock申请锁的进程生效。
  • flock默认工作在阻塞模式:调用flock(fd, LOCK_EX)时如果锁已被其他进程持有,调用会永久阻塞直到锁被释放,不会立刻返回错误。如果需要拿不到锁直接返回失败,需要传入LOCK_EX | LOCK_NB参数,此时拿锁失败会返回-1,置错误码为EWOULDBLOCK。
  • 如果需要强制拦截未持锁进程的读写(即强制锁),需要同时满足两个条件:文件所在文件系统挂载时指定mand参数开启强制锁支持、目标文件设置setgid位并关闭组执行权限(执行chmod g+s,g-x 文件名设置)。生产环境不推荐使用强制锁,语义隐患较多。

代码存在的问题

观察到的两个异常现象,基本都是代码实现不严谨导致的:

  1. 缺失必要头文件
    贴出的代码没有包含任何系统调用/库函数对应的头文件,编译时会产生大量隐式声明警告,直接运行会出现各类不可预期的行为:
    • open、O_RDWR宏定义需要引入<fcntl.h>,缺失的话编译器无法识别O_RDWR宏,会默认将其作为值为0的普通变量处理,对应只读打开标志O_RDONLY,此时write调用会因权限不足失败,这就是写入不生效的直接原因。
    • flock需要引入<sys/file.h>,write/close/sleep需要引入<unistd.h>,printf/perror需要引入<stdio.h>,缺失这些头文件会导致系统调用参数传递、返回值解析异常,很容易出现加锁状态判断错误。
  2. 未校验关键系统调用的返回值
    代码没有判断open的返回值,如果文件不存在、权限不足,open会返回-1,后续把无效fd传给flock/write会导致所有调用全部异常。另外测试第二个进程加锁时,如果没有加LOCK_NB参数,flock会阻塞在调用处不会返回,很容易被误判为加锁成功。
  3. 输出逻辑不严谨
    write.c中printf("%d",n)没有加换行符,而stdout默认是行缓冲模式,没有换行的输出可能不会立刻刷新到终端,容易误判返回值。

修正后可运行的测试代码

lock.c(持锁进程)

#include <fcntl.h>
#include <sys/file.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
    int fd = open("okas", O_RDWR);
    if (fd == -1) {
        perror("open file failed");
        return 1;
    }
    // 非阻塞模式申请排他锁
    int ret = flock(fd, LOCK_EX | LOCK_NB);
    if (ret == -1) {
        perror("get exclusive lock failed");
        close(fd);
        return 1;
    }
    printf("pid %d hold exclusive lock, running...\n", getpid());
    while (1) {
        sleep(1);
    }
    // 演示释放锁逻辑,实际死循环不会走到
    flock(fd, LOCK_UN);
    close(fd);
    return 0;
}

write.c(写入测试进程)

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
    int fd = open("okas", O_RDWR);
    if (fd == -1) {
        perror("open file failed");
        return 1;
    }
    // 如果要测试锁对写的互斥,可在这里加入flock加锁逻辑
    int ret = write(fd, "1", 1);
    if (ret == -1) {
        perror("write failed");
        close(fd);
        return 1;
    }
    printf("write %d byte success\n", ret);
    close(fd);
    return 0;
}

测试步骤

  1. 编译两个程序:gcc lock.c -o lock && gcc write.c -o write
  2. 提前创建测试文件:touch okas
  3. 第一个终端运行./lock,看到持锁成功的输出后,打开第二个终端再次运行./lock,会立刻返回Resource temporarily unavailable的错误,符合排他锁互斥预期。
  4. 第二个终端运行./write,会直接提示写入成功,查看文件会发现第一个字节被改为1,这就是建议性锁不强制拦截IO的正常表现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 18:27:40