Linux 支持的文件锁技术主要包括劝告锁(advisory lock)和强制锁(mandatory lock)这两种。此外,Linux 中还引入了两种强制锁的变种形式:共享模式强制锁(share-mode mandatory lock)和租借锁(lease)。
在 Linux 中,不论进程是在使用劝告锁还是强制锁,它都可以同时使用共享锁和排他锁(又称为读锁和写锁)。多个共享锁之间不会相互干扰,多个进程在同一时刻可以对同一个文件加共享锁。但是,如果一个进程对该文件加了排他锁,那么其他进程则无权再对该文件加共享锁或者排他锁,直到该排他锁被释放。所以,对于同一个文件来说,它可以同时拥有很多读者,但是在某一特定时刻,它只能拥有一个写者,它们之间的兼容关系如表所示。
锁间的兼容关系
|
|
|
---|---|---|
当前加上的锁
|
共享锁
|
排他锁
|
无
|
是
|
是
|
共享锁
|
是
|
否
|
排他锁
|
否
|
否
|
共享锁=读锁,排它锁=写锁
也就是说当前文件没有加锁时,此时共享锁和排他锁都能够加到此文件上
当前文件有共享锁时,此时只能在文件上加共享锁(同一个文件可以拥有很多读者),不能加排他锁
当前文件有排他锁时,不能在文件上继续加锁
进行对已加强制锁的文件进行操作时的行为
当前锁类型 | 阻塞读 | 阻塞写 | 非阻塞读 | 非阻塞写 |
---|---|---|---|---|
读锁 | 正常读取数据 | 阻塞 | 正常读取数据 | EAGAIN |
写锁 | 阻塞 | 阻塞 | EAGAIN | EAGAIN |
当前文件已经有一个读锁时,再加一个读锁(阻塞读,例如:fcntl(fd, F_SETLKW, &flock);非阻塞读:fcntl(fd, F_SETLK, &flock))是可以加上去的;如果再加一个写锁(阻塞写:导致阻塞;非阻塞写:返回errorno)
当文件有一个写锁时,同理。
文件中的每个字节在任一时刻只能拥有一种类型的锁:共享锁(读锁)、独占锁(写锁)或解锁。
command=F_SETLK时,对fildes指向的文件的某个区域加锁或解锁。加锁类型由l_type决定,区域由l_whence,l_start,l_len共同决定,这个函数立即返回成功(非-1值)或失败(-1)
command=F_SETLKW时,与上面的F_SETLK基本相同,只是在无法为文件添加锁时,函数将阻塞,直到可以添加锁或者获取到某个信号。
程序对某个文件拥有的所有锁都将在相应的文件描述符被关闭时自动清除。在程序结束时也会自动清除各种锁。
在讨论锁定时如果未提到死锁的危险,那么这个讨论就不能算是完整的。假设两个程序想要更新同一个文件。它们需要同时更新文件中的字节1和字节2。程序A选择首先更新字节2,然后再更新字节1。程序B则是先更新字节1,然后才是字节2。 两个程序同时启动。程序A锁定字节2,而程序B锁定字节1。然后程序A尝试锁定字节1,但因为这个字节已经被程序B锁定,所以程序A将在那里等待。接着程序B尝试锁定字节2,但因为这个字节已经被程序A锁定,所以程序B也将在那里等待。 这种两个程序都无法继续执行下去的情况,就被称为死锁(deadlock或deadly embrace)。这个问题在数据库应用程序中很常见,当许多用户频繁访问同一个数据时就很容易发生死锁。大多数的商业关系型数据库都能够检测到死锁并自动解开,但Linux内核不行。这时就需要采取一些外部干涉手段,例如强制终止其中一个程序来解决这个问题。 程序员必须对这种情况提高警惕。当有多个程序都在等待获得锁时,你就需要非常小心地考虑是否会发生死锁。在本例中,死锁是非常容易避免的:两个程序只需要使用相同的顺序来锁定它们需要的字节或锁定一个更大的区域即可。
Linux 2.6 中的文件锁:http://www.ibm.com/developerworks/cn/linux/l-cn-filelock/
fcntl函数:http://qcyhzwq001.lofter.com/tag/%E5%87%BD%E6%95%B0
获取锁定信息:http://docs.oracle.com/cd/E19253-01/819-7052/fileio-ex-1/index.html
记录上锁:http://www.cnblogs.com/siguoya/p/3512051.html
版权声明:本文为博主原创文章,未经博主允许不得转载。