Why the article
因为文件锁的事踩了点坑(还是在生产环境),花时间了解整理了一下。以下结论基本经过 demo 验证,先简略写写结论,总结总结历史,有空再补其他的。
Posix locks: fcntl/lockf | BSD locks: flock | |
---|---|---|
范围 | 字节范围锁 | 只能对整个文件加锁 |
类型 | 建议锁(默认)/ 强制锁(非 POSIX 标准,默认关闭) |
建议锁 |
关联关系 | 与进程关联( 标准 POSIX )/ 与文件描述符关联(非 POSIX 标准, 需特定参数, linux 3.15 支持) |
与文件描述符关联 |
网络文件系统 | 支持 NFS 不支持 ocfs2 |
支持 NFS(实现仿 fcntl, linux 2.6.12 支持) 支持 ocfs2 |
锁的类型
建议锁
- 只在合作进程(在读写文件之前尝试加锁)间有效。
- 其他进程非要读写是拦不住的。
强制锁
- 需要
mount -o mand
和chmod g+s,g-x lockfile
同时满足才行 - linux 内核会阻塞其他进程的 IO 请求
- 可以通过删除锁文件绕过
关联关系
与进程关联
- 当一个进程终止时,所建立的所有锁全部被释放
- 关闭一个文件描述符,会释放对该文件的所有锁,包括对其他指向相同文件的文件描述符加的锁
- 同一进程打开多个文件描述符
fd1
,fd2
- 对
fd1
加锁 - 关闭
fd2
-
fd1
上的锁会被释放
- 同一进程打开多个文件描述符
- fork 产生的子进程并不继承父进程所设置的锁
- 在执行
exec
后,新程序可以继承原程序的锁(如果对fd设置了close-on-exec,则exec前会关闭fd,相应文件的锁也会被释放)
与文件描述符关联
- 当一个文件描述符及其所有副本(包括子进程继承的和
dup
的)关闭时,才会释放对其建立的锁 -
fork
的子进程由于继承了文件描述符,所以也继承了其上的锁 - 子进程对继承的文件描述符上的锁进行修改/解锁,会影响到父进程的锁(对于
dup
出的副本同样试用) - 在执行
exec
后,新程序可以继承原程序的锁
fcntl/lockf 和 flock 的交互
- linux 2.0 后在本地文件系统上互不影响
- 在 NFS 上,
flock
由于底层实现仿造fcntl
的字节范围锁,所以两者会产生交互。
NOTE
- Linux
fcntl
的强制锁在设置的时候会和write/read
有 race condition。 -
fcntl
有死锁检测,而 flock 没有 - linux 3.12 之前,在 NFS 上设置的
fcntl
锁会因为 client 长时间(90s)与 nfs server 失去连接而丢失
参考文献
http://man7.org/linux/man-pages/man2/fcntl.2.html
http://man7.org/linux/man-pages/man2/flock.2.html
原理理解
http://blog.csdn.net/jnu_simba/article/details/8806654