The difference between fcntl(), lockf and flock
——lvyilong316
These three The function of the function is to lock the file, so what is the difference between them? First of all, flock and fcntl are system calls, and lockf is a library function. lockf is actually a package of fcntl, so the underlying implementation of lockf and fcntl are the same, and the effect of locking files is the same. When analyzing the differences later, in most cases fcntl and lockf are put together. Let's first look at the use of each function, and look at the differences between each function in terms of usage and effects.
l function prototype
#include
intflock(intfd,intoperation);//Applyorremoveanadvisorylockontheopenfilespecifiedbyfd, Just a suggestive lock
where fd is the file descriptor returned by the system call open. The operation options are:
LOCK_SH: shared lock
LOCK_EX: exclusive lock or exclusive lock
LOCK_UN: Unlocked.
LOCK_NB: Non-blocking (used with the above three operations)
Regarding the flock function, first of all, you must know that the flock function can only lock the entire file, not a certain part of the file. Lock, this is the first important difference from fcntl/lockf, which can lock a certain area of the file. Secondly, flock can only produce advisory locks. We know that Linux has mandatory locks (mandatorylock) and advisory locks (advisorylock). The so-called forced lock is easier to understand. It is the lock on your door. The most terrible thing is that there is only one key and only one process that can operate it. The so-called advisory lock is essentially a protocol. Before you access the file, you first check the lock. This is when the lock comes into play. If you are not so kind and just read and write regardless of the situation, then the advisory lock has no effect. effect. Those processes that comply with the protocol and check the lock before reading or writing are called cooperating processes. Again, the difference between flock and fcntl/lockf mainly lies in fork and dup.
(1) The lock created by flock is associated with the file open table entry (structfile), not fd. This means that after copying the file fd (through fork or dup), the lock can be operated through both fds (for example, locking through one fd and releasing the lock through another fd), that is to say, the child process inherits The lock of the parent process. However, when one of the fds is closed during the locking process, the lock will not be released (because the file structure is not released). The lock will not be released until all copied fds are closed. Test program into program one.
l Program 1
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>#include <stdio.h><br /></li><li>#include <unistd.h><br /></li><li>#include <stdlib.h><br /></li><li>#include <sys/file.h><br /></li><li>int main (int argc, char ** argv)<br /></li><li>{<br /></li><li>int ret;<br /></li><li>int fd1 = open("./tmp.txt",O_RDWR);<br /></li><li>int fd2 = dup(fd1);<br /></li><li>printf("fd1: %d, fd2: %d\n", fd1, fd2);<br /></li><li>ret = flock(fd1,LOCK_EX);<br /></li><li>printf("get lock1, ret: %d\n", ret);<br /></li><li>ret = flock(fd2,LOCK_EX);<br /></li><li>printf("get lock2, ret: %d\n", ret);<br /></li><li>return 0;<br /></li><li>}</li></ol>
The running result is as shown in the figure, for fd1 The lock does not affect the program's locking through fd2. For parent-child processes, refer to Procedure 2.
l Program 2
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>#include <stdio.h><br /></li><li>#include <unistd.h><br /></li><li>#include <stdlib.h><br /></li><li>#include <sys/file.h><br /></li><li>int main (int argc, char ** argv)<br /></li><li>{<br /></li><li>int ret;<br /></li><li>int pid;<br /></li><li>int fd = open("./tmp.txt",O_RDWR);<br /></li><li>if ((pid = fork()) == 0){<br /></li><li>ret = flock(fd,LOCK_EX);<br /></li><li>printf("chile get lock, fd: %d, ret: %d\n",fd, ret);<br /></li><li>sleep(10);<br /></li><li>printf("chile exit\n");<br /></li><li>exit(0);<br /></li><li>}<br /></li><li>ret = flock(fd,LOCK_EX);<br /></li><li>printf("parent get lock, fd: %d, ret: %d\n", fd, ret);<br /></li><li>printf("parent exit\n");<br /></li><li>return 0;<br /></li><li>}</li></ol>
The running result is as shown in the figure. The child process holds the lock. It does not affect the parent process acquiring the lock through the same fd, and vice versa.
(2) Use open to open the same file twice. The two fds obtained are independent (because the bottom layer corresponds to two file objects). It is locked through one of them and cannot be unlocked through the other, and in It cannot be locked until the previous one is unlocked. The test program is as follows:
l Program 3
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li style="text-align:left;">#include <stdio.h><br /></li><li style="text-align:left;">#include <unistd.h><br /></li><li style="text-align:left;">#include <stdlib.h><br /></li><li style="text-align:left;">#include <sys/file.h><br /></li><li style="text-align:left;">int main (int argc, char ** argv)<br /></li><li style="text-align:left;">{<br /></li><li style="text-align:left;">int ret;<br /></li><li style="text-align:left;">int fd1 = open("./tmp.txt",O_RDWR);<br /></li><li style="text-align:left;">int fd2 = open("./tmp.txt",O_RDWR);<br /></li><li style="text-align:left;">printf("fd1: %d, fd2: %d\n", fd1, fd2);<br /></li><li style="text-align:left;">ret = flock(fd1,LOCK_EX);<br /></li><li style="text-align:left;">printf("get lock1, ret: %d\n", ret);<br /></li><li style="text-align:left;">ret = flock(fd2,LOCK_EX);<br /></li><li style="text-align:left;">printf("get lock2, ret: %d\n", ret);<br /></li><li style="text-align:left;">return 0;<br /></li><li style="text-align:left;">}</li></ol>
The result is as shown in the figure. After acquiring the lock through fd1, it cannot Then acquire the lock through fd2.
(3) After using exec, the status of the file lock remains unchanged.
(4) flock cannot be used on NFS file systems. If you want to use file locks on NFS, please use fcntl.
(5) The flock lock is recursive, that is, two fds generated through dup or fork can be locked without deadlock.
l function prototype
#include
intlockf(intfd,intcmd,off_tlen);
fd is the open file descriptor returned by open.
The value of cmd is:
F_LOCK: Lock the file mutually. If the file is locked, it will be blocked until the lock is released.
F_TLOCK: Same as F_LOCK, but if the file is locked, it will not block and return an error.
F_ULOCK: Unlocked.
F_TEST: Test whether the file is locked. If the file is not locked, it returns 0, otherwise it returns -1.
len: is the length to be locked from the beginning of the current position of the file.
Through the functions of function parameters, it can be seen that lockf only supports exclusive locks and does not support shared locks.
#include
#include
intfcntl(intfd,intcmd,.../*arg*/);
structflock{
...
shortl_type;/*Typeoflock:F_RDLCK,F_WRLCK,F_UNLCK*/
shortl_whence;/*Howtointerpretl_start:SEEK_SET,SEEK_CUR,SEEK_END*/
off_tl_start;/*Startingoffsetforlock*/
off_tl_len;/*Numberofbytestolock*/
pid_tl_pid;/*PIDofprocessblockingourlock(F_GETLKonly)*/
...
};
文件记录加锁相关的cmd分三种:
F_SETLK:申请锁(读锁F_RDLCK,写锁F_WRLCK)或者释放所(F_UNLCK),但是如果kernel无法将锁授予本进程(被其他进程抢了先,占了锁),不傻等,返回error。
F_SETLKW:和F_SETLK几乎一样,唯一的区别,这厮是个死心眼的主儿,申请不到,就傻等。
F_GETLK:这个接口是获取锁的相关信息:这个接口会修改我们传入的structflock。
通过函数参数功能可以看出fcntl是功能最强大的,它既支持共享锁又支持排他锁,即可以锁住整个文件,又能只锁文件的某一部分。
下面看fcntl/lockf的特性:
(1)上锁可递归,如果一个进程对一个文件区间已经有一把锁,后来进程又企图在同一区间再加一把锁,则新锁将替换老锁。
(2)加读锁(共享锁)文件必须是读打开的,加写锁(排他锁)文件必须是写打开。
(3)进程不能使用F_GETLK命令来测试它自己是否再文件的某一部分持有一把锁。F_GETLK命令定义说明,返回信息指示是否现存的锁阻止调用进程设置它自己的锁。因为,F_SETLK和F_SETLKW命令总是替换进程的现有锁,所以调用进程绝不会阻塞再自己持有的锁上,于是F_GETLK命令绝不会报告调用进程自己持有的锁。
(4)进程终止时,他所建立的所有文件锁都会被释放,队医flock也是一样的。
(5)任何时候关闭一个描述符时,则该进程通过这一描述符可以引用的文件上的任何一把锁都被释放(这些锁都是该进程设置的),这一点与flock不同。如:
fd1=open(pathname,…);
lockf(fd1,F_LOCK,0);
fd2=dup(fd1);
close(fd2);
则在close(fd2)后,再fd1上设置的锁会被释放,如果将dup换为open,以打开另一描述符上的同一文件,则效果也一样。
fd1=open(pathname,…);
lockf(fd1,F_LOCK,0);
fd2=open(pathname,…);
close(fd2);
(6)由fork产生的子进程不继承父进程所设置的锁,这点与flock也不同。
(7)在执行exec后,新程序可以继承原程序的锁,这点和flock是相同的。(如果对fd设置了close-on-exec,则exec前会关闭fd,相应文件的锁也会被释放)。
(8)支持强制性锁:对一个特定文件打开其设置组ID位(S_ISGID),并关闭其组执行位(S_IXGRP),则对该文件开启了强制性锁机制。再Linux中如果要使用强制性锁,则要在文件系统mount时,使用_omand打开该机制。
那么flock和lockf/fcntl所上的锁有什么关系呢?答案时互不影响。测试程序如下:
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>#include <unistd.h><br /></li><li>#include <stdio.h><br /></li><li>#include <stdlib.h><br /></li><li>#include <sys/file.h><br /></li><li>int main(int argc, char **argv)<br /></li><li>{<br /></li><li>int fd, ret;<br /></li><li>int pid;<br /></li><li>fd = open("./tmp.txt", O_RDWR);<br /></li><li>ret = flock(fd, LOCK_EX);<br /></li><li>printf("flock return ret : %d\n", ret);<br /></li><li>ret = lockf(fd, F_LOCK, 0);<br /></li><li>printf("lockf return ret: %d\n", ret);<br /></li><li>sleep(100);<br /></li><li>return 0;<br /></li><li>}</li></ol>
测试结果如下:
$./a.out
flockreturnret:0
lockfreturnret:0
可见flock的加锁,并不影响lockf的加锁。两外我们可以通过/proc/locks查看进程获取锁的状态。
$psaux|grepa.out|grep-vgrep
123751188490.00.011904440pts/5S+01:090:00./a.out
$sudocat/proc/locks|grep18849
1:POSIXADVISORYWRITE1884908:02:8526740EOF
2:FLOCKADVISORYWRITE1884908:02:8526740EOF
我们可以看到/proc/locks下面有锁的信息:我现在分别叙述下含义:
1) POSIXFLOCK is relatively clear, which type of lock it is. The flock system call generates FLOCK, fcntl calls F_SETLK, F_SETLKW or lockf generates POSIX type. It can be seen that the types of locks generated by the two calls are different;
2) ADVISORY indicates that it is an advisory lock;
3) WRITE, as the name suggests, is a write lock and a read lock;
4) 18849 is the process ID that holds the lock. Of course, for locks of this type, there will be a situation where the process has exited.
5) 08:02:852674 indicates the primary device of the device where the corresponding disk file is located, the minor device number, and the inodenumber corresponding to the file.
6) 0 represents the actual position
7) EOF represents the end position. These two fields are more useful for fcntl types, and for flock they are always 0 and EOF.