为何fork()中使用flock()会通过不同文件描述符重复锁定同一文件?
问题分析与解决
你的代码出现这种现象,核心原因是进程调度的时序问题,加上锁的持有时间太短:
当
fork()后,父进程和子进程的执行顺序由操作系统调度器决定。如果父进程先完成整个流程:打开文件→加排他锁→打印→关闭文件(关闭文件会自动释放该进程持有的文件锁),此时子进程才开始执行,文件锁已经被释放,子进程自然能成功获取锁并打印。另外你的
open调用存在参数错误:open的第二个参数是打开标志(如O_WRONLY、O_CREAT),第三个参数才是文件权限(0600)。你把权限值放到了标志位参数里,属于未定义行为,正确写法:- 文件已存在时:
int id = open("shared.txt", O_WRONLY); - 需要创建文件时:
int id = open("shared.txt", O_WRONLY | O_CREAT, 0600);
- 文件已存在时:
验证互斥效果的修改方案
要看到预期的“一个进程锁定,另一个阻塞”效果,需要让持有锁的进程保持锁一段时间,比如在printf后添加sleep,避免锁被立即释放:
#include <stdio.h> #include <unistd.h> #include <sys/file.h> #include <sys/wait.h> #include <fcntl.h> int main() { int i = fork(); if (!i){ int id = open("shared.txt", O_WRONLY); if(flock(id, LOCK_EX) == 0) { printf("child\n"); sleep(5); // 持有锁5秒 } close(id); } else { int id = open("shared.txt", O_WRONLY); if(flock(id, LOCK_EX) == 0) { printf("parent\n"); sleep(5); // 持有锁5秒 } close(id); wait(NULL); } return 0; }
修改后,无论哪个进程先获取锁,都会持有锁5秒,另一个进程的flock会被阻塞,直到锁被释放,你会看到一个进程先打印,5秒后另一个进程才输出内容。
补充:flock核心特性
flock的锁默认是建议性锁,只有所有访问文件的进程都遵守锁协议时,互斥才会生效;- 锁与进程+文件inode绑定:同一个进程对同一个inode的多个文件描述符,锁是共享的;不同进程对同一个inode的文件描述符,排他锁互斥;
- 进程关闭任意一个指向该inode的文件描述符,或进程退出时,对应inode的
flock锁会自动释放。
内容的提问来源于stack exchange,提问作者Єгорій
相关产品推荐
相关产品推荐

