Linux下C语言lockf、flock、fcntl文件锁含义及相关疑问咨询
嘿,作为从Windows转Linux做C开发的过来人,太懂你这种困惑了!咱们一步步拆解你的问题:
Linux vs Windows 文件锁的核心差异
你观察到的现象完全正常,这俩系统的文件锁设计理念天差地别:
- Windows是强制性锁:系统内核会主动拦截所有对锁定文件的非法操作(修改、删除、打开等),只要一个进程锁了文件,其他进程根本碰不了,完全是「硬拦截」。
- Linux默认是劝告性锁(Advisory Lock):
lockf、flock、fcntl这几个函数创建的锁,本质是给进程之间约定好的信号,内核不会主动阻止不遵守规则的进程。也就是说,只有当其他进程在操作文件前,主动调用fcntl或相关函数检查锁的状态,才会遵守锁的限制。像桌面文件管理器、echo > file这种工具,根本不会去检查锁,所以该删改还是能删改。
你用lslock看到的TYPE/POSIX MODE/WRITE START/0 END/0是fcntl创建的POSIX范围锁,START/0 END/0表示锁定了整个文件,但它依然是劝告性的——这就是为什么其他进程可以无视它。
要不要搞Linux的强制性锁?
Linux其实也支持强制性锁,但非常不推荐用:
- 你需要挂载文件系统时加上
-o mand参数(比如mount -o mand /dev/sda1 /mnt); - 还要给目标文件设置sgid位,同时去掉group执行权限(
chmod g+s,g-x yourfile); - 这种锁兼容性极差,很多文件系统(比如ext4的某些配置)不支持,而且会带来性能损耗。
业界通用的做法还是用劝告性锁,在你自己的所有进程里,操作文件前先检查并获取锁,以此来协调进程间的访问。
NFS下的字节范围锁操作
NFS对文件锁的支持确实有特殊要求:
- 必须用
fcntl的范围锁:flock完全不被NFS支持,lockf其实是fcntl的封装,所以优先直接用fcntl; - 必须明确指定字节范围:NFS不支持模糊的「整个文件」锁(虽然
START/0 END/0在本地文件系统表示整个文件,但NFS可能不认),最好明确锁定从文件开头到末尾的所有字节,甚至包括未来文件增长的部分。
给你一个C语言的示例代码,用来在NFS上获取写锁:
#include <fcntl.h> #include <stdio.h> #include <unistd.h> int main() { int fd = open("/nfs/path/yourfile", O_RDWR | O_CREAT, 0644); if (fd == -1) { perror("open failed"); return 1; } struct flock lock; lock.l_type = F_WRLCK; // 写锁 lock.l_whence = SEEK_SET; // 从文件开头开始 lock.l_start = 0; // 起始字节 lock.l_len = 0; // 0表示从start到EOF,包括未来新增的字节 lock.l_pid = getpid(); // 尝试获取锁,非阻塞;如果要阻塞等待用F_SETLKW if (fcntl(fd, F_SETLK, &lock) == -1) { perror("fcntl lock failed"); close(fd); return 1; } printf("Got write lock on NFS file\n"); // 这里做你的文件操作... // 释放锁 lock.l_type = F_UNLCK; fcntl(fd, F_SETLK, &lock); close(fd); return 0; }
另外还要注意:NFS的文件锁依赖rpc.lockd和rpc.statd服务,必须确保这两个服务在NFS服务器和客户端都正常运行,否则锁会失效。
刚转Linux的时候我也纠结过「为什么锁了还能改」,后来才明白Linux的哲学是「信任进程但提供协调工具」,只要你的进程都遵守锁的约定,就不会有问题。
内容的提问来源于stack exchange,提问作者Mohammad Nabil
相关产品推荐
相关产品推荐

