引言
在多进程环境下,多个进程同时读写一个文件,如果不进行同步,就可能导致不期待的结果,如后一个进程覆盖了前一个进程写的内容。Unix为此提供了一种强大的解决办法:记录锁
记录锁
记录锁本质上就是对文件加读写锁,但是它不仅可以对整个文件加锁,也可以对文件的某块区域加锁,这正是其强大之处。
其主要由两部分构成,操作类型和加锁区域
struct flock{short l_type; /* 操作类型:加读锁(F_RDLCK),加写锁(F_WRLCK),解锁(F_UNLCK) */// 加锁区域off_t l_start; /* 开始位置 */off_t l_len; /* 区域长度 , 为0时,表示从开始位置到文件末尾的所有区域都加锁 */......
}
加锁和解锁
通过调用fcntl,并设置cmd为F_SETLK,再传入flock结构,就可以加锁解锁了
#include <fcntl.h>
int fcntl(int fd, int cmd, .../* struct flock *flockptr */);
值得一提的是,如果先对某块区域加了锁,解锁时可以只部分解锁。
当对于文件的某个区域加锁时,这条加锁记录是放在vnode节点上的
释放锁
除了调用fcntl释放锁外,还有一些隐式释放的方法。
- 调用close关闭文件时,会释放进程再这个文件上加的锁
- 进程退出时,会调用close方法关闭文件描述符,也就会释放锁
锁继承
当fork子进程时,子进程不会继承父进程加的记录锁,根本原因在于锁记录存在于vnode上,而vnode是内核数据,fork只会复制用户地址空间的数据,而且子进程的ID和父进程也不同,所以子进程不会继承父进程的加的记录锁
建议性锁和强制性锁
当一个进程调用fcntl对文件加了记录锁后,其他进程是可以直接调用read和write函数读写该文件的,这时加的锁称为建议性锁。
如果需要在调用read和write时,检查读写区域是否加锁,就需要加强制性锁。通过设置文件的“set-group-id”位,并取消文件组执行位,调用fcntl就加的是强制性锁了