Linux文件锁学习-flock, lockf, fcntl
参考 linux中fcntl()、lockf、flock的区别
这三个函数的作用都是给文件加锁,那它们有什么区别呢?
首先flock和fcntl是系统调用,而lockf是库函数。lockf实际上是fcntl的封装,所以lockf和fcntl的底层实现是一样的,对文件加锁的效果也是一样的。后面分析不同点时大多数情况是将fcntl和lockf放在一起的。
下面首先看每个函数的使用,从使用的方式和效果来看各个函数的区别。
1. flock
l 函数原型
#include<sys/file.h>
int flock(int fd, int operation); // Apply or remove an advisory lock on the open file specified by fd,只是建议性锁
其中fd是系统调用open返回的文件描述符,operation的选项有:
LOCK_SH :共享锁
LOCK_EX :排他锁或者独占锁
LOCK_UN : 解锁。
LOCK_NB:非阻塞(与以上三种操作一起使用)
关于flock函数,首先要知道flock函数只能对整个文件上锁,而不能对文件的某一部分上锁,这是于fcntl/lockf的第一个重要区别,后者可以对文件的某个区域上锁。
其次,flock只能产生劝告性锁。我们知道,linux存在强制锁(mandatory lock)和劝告锁(advisory lock)。所谓强制锁,比较好理解,就是你家大门上的那把锁,最要命的是只有一把钥匙,只有一个进程可以操作。所谓劝告锁,本质是一种协议,你访问文件前,先检查锁,这时候锁才其作用,如果你不那么kind,不管三七二十一,就要读写,那么劝告锁没有任何的作用。而遵守协议,读写前先检查锁的那些进程,叫做合作进程。
再加上,flock可以有共享锁和排它锁,lockf只支持排它锁,但是fcntl里面参数flock可以有RDLCK读锁。
再次,flock和fcntl/lockf的区别主要在fork和dup时候的区别,后面有讲。
另外,flock不能再NFS文件系统上使用,如果要在NFS使用文件锁,请使用fcntl。
然后,后面讲了一堆fork和dup之后flock的表现。可以去看原文。
2. lockf与fcntl
l 函数原型
#include <unistd.h>
int lockf(int fd, int cmd, off_t len);
fd为通过open返回的打开文件描述符。
cmd的取值为:
F_LOCK:给文件互斥加锁,若文件以被加锁,则会一直阻塞到锁被释放。
F_TLOCK:同F_LOCK,但若文件已被加锁,不会阻塞,而回返回错误。
F_ULOCK:解锁。
F_TEST:测试文件是否被上锁,若文件没被上锁则返回0,否则返回-1。
len:为从文件当前位置的起始要锁住的长度。
通过函数参数的功能,可以看出lockf只支持排他锁,不支持共享锁。
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );(用法:int ret = fcntl(fd, F_SETLKW, &lock);)
其实的lock就是下面的数据结构:
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) */
...
};
文件记录加锁相关的cmd 分三种:
F_SETLK:申请锁(读锁F_RDLCK,写锁F_WRLCK)或者释放所(F_UNLCK),但是如果kernel无法将锁授予本进程(被其他进程抢了先,占了锁),不傻等,返回error。
F_SETLKW:和F_SETLK几乎一样,唯一的区别,这厮是个死心眼的主儿,申请不到,就傻等。
F_GETLK:这个接口是获取锁的相关信息: 这个接口会修改我们传入的struct flock。
通过函数参数功能可以看出fcntl是功能最强大的,它既支持共享锁又支持排他锁,即可以锁住整个文件,又能只锁文件的某一部分。
下面看fcntl/lockf的特性:
1. 可递归(同flock)
2. 加读锁(共享锁)文件必须是读打开的,加写锁(排他锁)文件必须是写打开。
3. 进程不能使用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也不同。(因为flock创建的锁是和文件打开表项(struct file)相关联的,而不是fd,所以复制出了fd都可以操作这把锁,所以子进程继承了父进程的锁。flock里面要关闭所有复制出的fd,锁才会释放)
7. 在执行exec后,新程序可以继承原程序的锁,这点和flock是相同的。(如果对fd设置了close-on-exec,则exec前会关闭fd,相应文件的锁也会被释放)。
8. 支持强制性锁(跟flock不同)。下面会讲。
3. 两种锁的关系
那么flock和lockf/fcntl所上的锁有什么关系呢?答案时互不影响。测试程序如下:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/file.h>
int main(int argc, char **argv)
{
int fd, ret;
int pid;
fd = open("./tmp.txt", O_RDWR);
ret = flock(fd, LOCK_EX);
printf("flock return ret : %d\n", ret);
ret = lockf(fd, F_LOCK, 0);
printf("lockf return ret: %d\n", ret);
sleep(100);
return 0;
}
测试结果如下:
$./a.out
flock return ret : 0
lockf return ret: 0
可见flock的加锁,并不影响lockf的加锁。两外我们可以通过/proc/locks查看进程获取锁的状态。
$ps aux | grep a.out | grep -v grep
123751 18849 0.0 0.0 11904 440 pts/5 S+ 01:09 0:00 ./a.out
$sudo cat /proc/locks | grep 18849
1: POSIX ADVISORY WRITE 18849 08:02:852674 0 EOF
2: FLOCK ADVISORY WRITE 18849 08:02:852674 0 EOF
我们可以看到/proc/locks下面有锁的信息:我现在分别叙述下含义:
1) POSIX FLOCK 这个比较明确,就是哪个类型的锁。flock系统调用产生的是FLOCK,fcntl调用F_SETLK,F_SETLKW或者lockf产生的是POSIX类型,可见两种调用产生的锁的类型是不同的;
2) ADVISORY表明是劝告锁;
3) WRITE顾名思义,是写锁,还有读锁;
4) 18849是持有锁的进程ID。当然对于flock这种类型的锁,会出现进程已经退出的状况。
5) 08:02:852674表示的对应磁盘文件的所在设备的主设备好,次设备号,还有文件对应的inode number。
6) 0表示的是所的其实位置
7) EOF表示的是结束位置。 这两个字段对fcntl类型比较有用,对flock来是总是0 和EOF。
fcntl支持强制性锁:对一个特定文件打开其设置组ID位(S_ISGID),并关闭其组执行位(S_IXGRP),则对该文件开启了强制性锁机制。再Linux中如果要使用强制性锁,则要在文件系统mount时,使用-omand打开该机制。
见这篇文章:
http://blog.jobbole.com/16882/
用fcntl加锁:
#include <stdio.h>
#include <fcntl.h> int main(int argc, char **argv) {
if (argc > 1) {
int fd = open(argv[1], O_WRONLY);
if(fd == -1) {
printf("Unable to open the file\n");
exit(1);
}
static struct flock lock; lock.l_type = F_WRLCK;
lock.l_start = 0;
lock.l_whence = SEEK_SET;
lock.l_len = 0;
lock.l_pid = getpid(); int ret = fcntl(fd, F_SETLKW, &lock);
printf("Return value of fcntl:%d\n",ret);
if(ret==0) {
while (1) {
scanf("%c", NULL);
}
}
}
}
使用mount命令带“mand”参数来重新挂载根文件系统,如下所示。这将在文件系统级别使能强制锁功能。注意:你必须切换到root用户才能执行下面的命令。
# mount -oremount,mand /
在可执行的(file_lock所在的)目录中创建两个名为“advisory.txt”和“mandatory.txt”的文件。对于“mandatory.txt”使能Set-Group-ID,同时不使能Group-Execute-Bit,如下所示:
# touch advisory.txt
# touch mandatory.txt
# chmod g+s,g-x mandatory.txt
测试协同锁:
执行示例程序,以“advisory.txt”作为参数。 # ./file_lock advisory.txt
此程序将等待用户的输入。 从另一个终端或控制台,尝试输入以下命令行(不检查锁,直接输入): # ls >>advisory.txt
在上面的例子中,ls命令会将其输出写入到advisory.txt文件中。即使我们获得了一个写入锁,仍然会有一些进程(非合作)能够往文件里写入数据。这就是所谓的“协同”锁。
测试强制锁:
再次执行示例程序,以“mandatory.txt”作为参数。 # ./file_lock mandatory.txt 从另一个终端或控制台,尝试输入以下命令行: # ls >>mandatory.txt
在上面的例子中,ls命令在将其输出写入到mandatory.txt文件之前,会等待文件锁被删除。虽然它仍然是一个非合作进程,但强制锁起了作用。
(完)
Linux文件锁学习-flock, lockf, fcntl的更多相关文章
- 每天进步一点点——Linux文件锁编程flock
转载请注明出处:http://blog.csdn.net/cywosp/article/details/30083015 1. 场景概述 在多线程开发中.相互排斥锁能够用于对临界资源的保护,防 ...
- linux 文件锁flock,lockf,fcntl
1.flock,lockf,fcntl之间区别 先上结论:flock是文件锁,锁的粒度是整个文件,就是说如果一个进程对一个文件加了LOCK_EX类型的锁,别的进程是不能对这个文件加锁的. lockf是 ...
- 文件锁-fcntl flock lockf
这三个函数的作用都是给文件加锁,那它们有什么区别呢? 首先flock和fcntl是系统调用,而lockf是库函数.lockf实际上是fcntl的封装,所以lockf和fcntl的底层实现是一样的,对文 ...
- linux文件锁flock【转】
转自: https://www.cnblogs.com/kex1n/p/7100107.html linux文件锁flock 在多个进程同时操作同一份文件的过程中,很容易导致文件中的数据混乱,需要 ...
- Linux文件锁flock
Linux文件锁flock 在多个进程同时操作同一份文件的过程中,很容易导致文件中的数据混乱,需要锁操作来保证数据的完整性,这里介绍的针对文件的锁,称之为“文件锁”-flock. flock,建议性锁 ...
- Linux 文件锁flock 实现两个进程相互监听存活状态
表头文件 #include<sys/file.h> 定义函数 int flock(int fd,int operation); 函数说明 flock()会依参数operation所指 ...
- Linux文件锁flock ,检测进程是否已经存在
在多个进程同时操作同一份文件的过程中,很容易导致文件中的数据混乱,需要锁操作来保证数据的完整性,这里介绍的针对文件的锁,称之为“文件锁”-flock. 头文件:#include<sys/fil ...
- Linux 文件锁
当多个进程同时访问操作同一个文件时,我们怎么保证文件数据的正确性. linux通常采用的方法是文件上锁,来避免共享资源的产生竞争状态. 文件锁包括建议性锁和强制性的锁: 建议性的锁 :顾名思义,相对温 ...
- Linux文件锁【转】
本文转载自:http://blog.csdn.net/dragon_li_chen/article/details/17147911 一.文件锁的分类: 翻阅参考资料,你会发现文件锁可以进行很多的分类 ...
随机推荐
- POJ 3419 Difference Is Beautiful(RMQ+二分 或者 模拟)
Difference Is Beautiful Time Limit:5000MS Memory Limit:65536KB 64bit IO Format:%lld & %l ...
- Chapter 1 First Sight——24
He looked away quickly, more quickly than I could, though in a flush of embarrassment I dropped my e ...
- JSP内置对象--out对象(了解即可)
out对象是javax.servlet.jsp.JspWriter类的实例化对象,主要功能就是完成页面的输出操作,使用println()或print()输出.但是使用纪律很少,都会使用表达式完成输出的 ...
- psy & vr
技术指标及应用法则:PSY和VR 一.PSY(Psychologial Line) 1. PSY的参数 2. PSY的应用法则 二.VR(Volume Ratio) 1. VR的参数 2. VR的 ...
- javascript之定义函数时 this 和prototype区别
注:原文 http://www.2cto.com/kf/201406/307790.html 这里作为学习,写在这里 在面向对象的方式编写js脚本时,定义实例的方法主要有两种:this.XXX = f ...
- 转 oracle 开发 第03章 sqlplus
目录 1.查看表结构 desc 2.编辑SQL语句 append.list.change.run 3.保存.检索并运行文件 save.get.start.edit.spool 4.格式化列 colum ...
- 页面加载完毕执行多个JS函数
通常我们需要在打开页面时加载脚本,这些脚本必须在页面加载完毕后才可以执行,因为这时候DOM才完整,可以利用window.onload确保这一点,如:window.onload=firstFunctio ...
- Struts1.x教程:配置文件总结
要想使用Struts,至少要依靠两个配置文件:web.xml和struts-config.xml.其中web.xml用来安装Struts框架.而struts-config.xml用来配置在Struts ...
- USACO Section 1.3 Mixing Milk 解题报告
题目 题目描述 Merry Milk Makers 公司的业务是销售牛奶.它从农夫那里收购N单位的牛奶,然后销售出去.现在有M个农夫,每个农夫都存有一定量的牛奶,而且每个农夫都会有自己的定价.假设所有 ...
- CentOS 7 安装 GlusterFS
CentOS 7 GlusterFS 环境说明: 3台机器安装 GlusterFS 组成一个集群. 使用 docker volume plugin GlusterFS 服务器: 10.6.0.140 ...