文件锁定(Beginnig Linux Programming 4th) - oceaneys/A-CD-Record-Management-System GitHub Wiki
文件是系统中数据共享的一种方式,当有多个用户访问同一个文件时,就需要对整个文件或文件区域进行并发控制 ———— 文件锁定
文件锁定的方式有两种:锁文件 和 区域锁定
锁文件
本质是一个普通文件,只是其是针对某个资源而创建的
其他程序可以通过检查这个文件是否存,来判断其本身是否可以访问该锁文件对应的资源。
锁文件的创建必须是原子的,通常的方式:open("/tm/LCK.test", O_RDWR | O_CREAT | O_EXCL, 0444)
临界区
如果一个程序在他执行时,只需要独占某个资源一段很短的时间 ———— 这用术语来说,通常被称为临界区。(P223,4b)
程序在进入临界区时用open系统调用创建锁文件,然后在退出临界区时用unlink系统调用删除该锁文件。
区域锁定
文件段锁定 或 文件区域锁定
在访问同一个大型的共享文件时,需要对文件的某个区域(连续的字节区间)进行独占访问,可以通过区域锁定来实现。
系统调用fcntl和lockf可以实现区域锁定,fcntl较lockf更为灵活,一般用fcntl实现。同一个程序中最好只用一种方式,混用时的结果没有定义。
fcntl(int fields, int command, struct flock *flock_structure)
command有三种取值:
F_GETLK : 获取fileds指向文件的锁信息,不会锁定文件。
F_SETLK : 对fileds指向文件的某个区域加锁或解锁
F_SETLKW : 等待直到对fileds指向的文件的某个区域加锁或解锁成功
---------------------------------------------------------
struct flock{
short l_type;
short l_whence;
off_t l_start;
off_t l_len;
pid_t l_pid;
}
l_type取值:
F_FDLCK: 共享锁(读锁),不同进程可以同时持有同一文件的同一区域的共享锁,和其他锁互斥
F_UNLCK: 解锁,用来清除锁
F_WRLCK: 独占锁(写锁),只有一个进程可以在文件的任意区域持有一把独占锁,和其他锁互斥
**文件中的每个字节在任一时刻只能持有一种类型的锁:共享锁、独占锁或解锁。**
l_whence取值如下:(其定义了l_start的相对偏移值)
SEEK_SET: 文件头,l_start表示距离文件头的字节数
SEEK_CUR: 当前位置,l_start表示距离当前位置的字节数
SEEK_END: 文件尾,l_start表示距离文件尾的字节数
l_len是字节数
l_pid是持有锁的进程号
建议锁和强制锁
文件锁定的方式都是建议锁,加锁后并不能真正阻止你读写文件中的数据。其本质上是保护临界区数据的一种协议,即在进入临界区前加锁,离开时解锁。
应用程序中的其他并发控制方式(如果是锁实现),也大都是建议锁(鄙人见识而已)
强制锁的案例,是多用户打开一个文件时,后打开的文件会提示以下信息:
Swap file ".lock2.c.swp" already exists!
[O]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort:
该提示如果默认时Q(uit)的处理方式,则就相当于强制锁。(个人理解)
死锁
A、B资源在两个临界区,即各对应一把锁。
程序1的访问顺序是A->B,先拿A锁,没有解锁情况下,再拿B锁 程序2的访问顺序是B->A,先拿B锁,没有解锁情况下,在那A锁
程序1和程序2同时运行,就会出现死锁: 程序1想拿B锁,但是B锁被程序2持有;程序2想拿A锁,但是A锁被程序1持有。
(这里只描述死锁现象,没有考虑现实中是否有上述案例)
解决办法
- 访问顺序一致(统一访问顺序为A->B,或则B->A)
- 先释放占有资源(程序1释放A锁后再拿B锁,同理程序2)
- 一次性占有所有资源(A\B资源一把锁)