记录锁
- 定义
记录锁:当一个进程对一个文件的某个部分或者整个文件作读操作或者修改时,记录锁可以阻止另一个进程修改文件的同一区域。
由其定义,可以知:
- 记录锁是对文件的一定范围,包括整个文件进行保护
- 记录锁的3个要素是:进程ID,文件范围,操作。也就是说判断记录锁是否产生排斥需要依据这3点。
同一个进程中,即使锁操作的文件范围冲突了,或者读写类型操作冲突了,最终产生的结果是后一个锁覆盖前一个锁,而不会出现冲突。
- 实现函数
linux中记录锁通过fcntl实现
#include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, ... /* strcut flock *flck */ );
fd,对应要加锁的文件描述符, strcut flock flck 描述了一个互斥锁,结构体定义:
struct flock { short l_type; /* Type of lock: F_RDLCK, F_WRLCK, F_UNLCK */ short l_whence; /* How to interpret l_start: SEEK_SET, SEEK_CUR, SEEK_END */ off_t l_start; /* Starting offset for lock */ off_t l_len; /* Number of bytes to lock */ pid_t l_pid; /* PID of process blocking our lock (F_GETLK only) */ };
l_type成员描述记录锁的类型,包括: F_RDLCK,独占性写锁,F_WRLCK,共享读锁,F_UNLCK,解锁
l_whence, l_start, l_len共同描述了一个文件范围: 从文件【(SEEK_SET,开头),(SEEK_CUR,当前位置),(SEEK_END,文件结尾)】,偏移 l_start后长度为 l_len的一个范围。
l_whence, l_start决定范围的起点,l_len决定范围的终点,如果l_len设置为0,则意思是从起点开始一直延伸到文件可扩展的最大范围,这个最大范围不是指文件的结尾,它可以超过文件的结尾,也就是说是动态的,随着文件的变大而变大。
l_pid: 当出现锁冲突时,通过F_GETLK得到占有文件范围的进程pid。
读写的兼容性:
fcntl的cmd包括:
F_GETLK:
主要用于测试锁是否冲突,如果出现了锁冲突,则flck结构体返回已存在锁的信息,否则flck->l_type被设置为 F_UNLCK,其他成员不变。
F_SETLK:
设置由flck描述的锁,如果出现错误,则说明锁出现了冲突,如果需要解除某个锁,可以将type设置为F_UNLCK。
F_SETLKW:
F_SETLK的阻塞版本,如果请求设置的锁出现冲突,则进程进入休眠直到冲突解除或者进程被信号唤醒。
系统将自动维护锁的分裂和合并,如下图,首先对100-199区间加锁,后面又对150这个字节解锁,那么文件将持有2把锁,这时如果有对150字节加锁,于是锁的范围又合并为左边图那样,持有的锁又变成了1个。
- 注意
F_GETLK不能用来测试进程自身是否在某个区域加了锁,因为F_GETLK是用来返回是否有另一个进程持有锁阻止本线程加锁。而进程本身的锁不可能出现冲突,只会出现后来的锁覆盖原先的锁的现象。