使用flock加排他锁后,父子进程仍可同时写入文件的问题
为什么flock加锁后两个进程仍能写入文件?
核心原因是**flock是劝告性锁(Advisory Lock)**,它不会强制阻止进程写入文件,只有当进程主动检查并遵守锁规则时,锁才会生效。你的代码里,即使flock获取锁失败(非阻塞模式下返回-1),进程依然执行了write操作,所以两个进程都能写入。
你的代码问题点
- 未处理锁失败的情况:你在
flock失败后仅调用perror打印错误,没有终止后续的write逻辑,导致未拿到锁的进程依然能写入文件。 - 打开文件无追加模式:用
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,提问作者Єгорій
相关产品推荐
相关产品推荐

