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

使用flock加排他锁后,父子进程仍可同时写入文件的问题

为什么flock加锁后两个进程仍能写入文件?

核心原因是**flock是劝告性锁(Advisory Lock)**,它不会强制阻止进程写入文件,只有当进程主动检查并遵守锁规则时,锁才会生效。你的代码里,即使flock获取锁失败(非阻塞模式下返回-1),进程依然执行了write操作,所以两个进程都能写入。

你的代码问题点

  1. 未处理锁失败的情况:你在flock失败后仅调用perror打印错误,没有终止后续的write逻辑,导致未拿到锁的进程依然能写入文件。
  2. 打开文件无追加模式:用O_WRONLY打开文件时,两个进程的写入会互相覆盖,虽然这不是锁失效的原因,但会导致写入结果混乱。

修正方案

有两种常见的修正方式,根据需求选择:

方案1:阻塞等待锁(保证所有进程都能写入)

去掉LOCK_NB参数,让未拿到锁的进程阻塞等待,直到锁被释放后再执行写入:

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

int main() {
    int i = fork();

    if (!i) {
        // 子进程
        int id = open("shared.txt", O_WRONLY | O_APPEND | O_CREAT, 0600); // 加O_CREAT确保文件存在
        if (id == -1) {
            perror("open_ch");
            return 1;
        }
        // 阻塞等待排他锁
        if (flock(id, LOCK_EX) == -1) {
            perror("flock_ch");
            close(id);
            return 1;
        }
        if (write(id, "child\n", 6) == -1) {
            perror("write_ch");
        } else {
            printf("child did it\n");
        }
        sleep(3);
        close(id); // 关闭文件时自动释放锁
    } else {
        // 父进程
        int id = open("shared.txt", O_WRONLY | O_APPEND | O_CREAT, 0600);
        if (id == -1) {
            perror("open_pr");
            return 1;
        }
        if (flock(id, LOCK_EX) == -1) {
            perror("flock_PR");
            close(id);
            return 1;
        }
        if (write(id, "parent\n", 7) == -1) {
            perror("write_pr");
        } else {
            printf("parent did it\n");
        }
        sleep(3);
        close(id);
        wait(NULL);
    }
    return 0;
}

方案2:非阻塞模式,拿不到锁就放弃写入

保持LOCK_NB,但在flock失败时直接退出进程,不执行写入:

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

int main() {
    int i = fork();

    if (!i) {
        int id = open("shared.txt", O_WRONLY | O_APPEND | O_CREAT, 0600);
        if (id == -1) {
            perror("open_ch");
            return 1;
        }
        // 非阻塞尝试获取排他锁
        if (flock(id, LOCK_EX | LOCK_NB) == -1) {
            perror("flock_ch");
            close(id);
            return 1; // 拿不到锁直接退出
        }
        if (write(id, "child\n", 6) == -1) {
            perror("write_ch");
        } else {
            printf("child did it\n");
        }
        sleep(3);
        close(id);
    } else {
        int id = open("shared.txt", O_WRONLY | O_APPEND | O_CREAT, 0600);
        if (id == -1) {
            perror("open_pr");
            return 1;
        }
        if (flock(id, LOCK_EX | LOCK_NB) == -1) {
            perror("flock_PR");
            close(id);
            return 1;
        }
        if (write(id, "parent\n", 7) == -1) {
            perror("write_pr");
        } else {
            printf("parent did it\n");
        }
        sleep(3);
        close(id);
        wait(NULL);
    }
    return 0;
}

额外说明

  • flock的锁与文件描述符绑定,关闭文件描述符时会自动释放锁,显式调用flock(id, LOCK_UN)不是必须的,但可以让逻辑更清晰。
  • 打开文件时添加O_APPEND,可以保证多个进程写入的内容追加到文件末尾,避免互相覆盖,这是多进程写文件的标准做法。
  • 劝告性锁的核心是所有访问文件的进程必须主动检查锁,如果有进程跳过锁检查直接写,flock无法阻止它。

内容的提问来源于stack exchange,提问作者Єгорій

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 03:45:46