linux 文件锁flock,lockf,fcntl
1、flock,lockf,fcntl之间区别
先上结论:flock是文件锁,锁的粒度是整个文件,就是说如果一个进程对一个文件加了LOCK_EX类型的锁,别的进程是不能对这个文件加锁的。
lockf是对fcntl的封装,这两个东西在内核上的实现是一样的。它们的粒度是字节,不同的进程可以对相同的文件不同字节加LOCK_EX类型的锁。
2、linux文件系统
在详解锁的实现机制前,我们先来看一下linux文件系统的实现。

相信大家都看过这样一副图。与进程相关的是文件描述符表,文件表和i-node都是系统级别的。当我们在进程中打开一个文件时,文件描述符里就会产生一个文件描述符表项与之对应,同样的系统内也会有文件句柄和相应的i-node,我们需要注意的是多个文件表项(同一个进程或不同进程)可以指向同一个文件句柄。
2、 flock锁的实现机制
flock在实现上关联到的是文件描述符(上图中文件描述符部分),这就意味着如果我们在进程中复制了一个文件描述符,那么使用flock对这个描述符加的锁也会在新复制出的描述符中继续引用。我们可以写如下代码测试:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/file.h>
#include <wait.h>
#define PATH "/tmp/lock"
int main()
{
int fd;
pid_t pid;
fd = open(PATH, O_RDWR | O_CREAT | O_TRUNC, );
flock(fd, LOCK_EX);
printf("%d: locked!\n", getpid());
pid = fork();
if (pid == ) {
// fd = open(PATH, O_RDWR|O_CREAT|O_TRUNC, 0644);
flock(fd, LOCK_EX);
printf("%d: locked!\n", getpid());
exit();
}
wait(NULL);
unlink(PATH);
exit();
}
输出结果:
Sangfor:aCMP/acmp-fefcfe3a1674 ~/test o ./a.out
: locked!
: locked!
由结果可见,父进程已经持有互斥锁的情况下,子进程应该对文件加锁失败才符合我们的预期。但是子进程确加锁成功。原因就在于flock的实现是关联文件描述符。
子进程由父进程创建,子进程的文件描述符表和父进程的一模一样,在fork()子进程后,子进程本身就持有该文件的互斥锁。同样的道理,对文件描述符dup(), dup2()都会有这样的问题。怎么解决这个问题呢?
1、重新open这个文件,使用新的文件描述符
fd = open(PATH, O_RDWR|O_CREAT|O_TRUNC, );
我们将上述注释掉的代码打开,重新编译执行,输出结果如下:
Sangfor:aCMP/acmp-fefcfe3a1674 ~/test o ./a.out
: locked!
这次子进程没有能上锁,重新open这个文件会创建一个新的文件描述符与父进程进程而来的描述符是不相关的,所以就符合我们预期的效果。
另外要注意:除非文件描述符被标记了close-on-exec标记,flock锁和lockf锁都可以穿越exec,在当前进程变成另一个执行镜像之后仍然保留。
3、lockf的实现机制
lockf的实现是关联到内核i-node的(上图内核部分),每次加锁都会在i-node节点上挂一个flock的结构:
struct flock
{
short l_type;/*F_RDLCK, F_WRLCK, or F_UNLCK*/
off_t l_start;/*相对于l_whence的偏移值,字节为单位*/
short l_whence;/*从哪里开始:SEEK_SET, SEEK_CUR, or SEEK_END*/
off_t l_len;/*长度, 字节为单位; 0 意味着缩到文件结尾*/
pid_t l_pid;/*returned with F_GETLK*/
};
对LOCK_EX类型的锁来说,内核中最多只有一份这样的数据,所以即使文件描述符是从父进程进程过来或dup()产生的,对同一个节点加锁都会失败。我们写如下代码测试一下:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/file.h>
#include <wait.h>
#define PATH "/tmp/lock" int main()
{
int fd;
pid_t pid;
fd = open(PATH, O_RDWR | O_CREAT | O_TRUNC, );
lockf(fd, F_LOCK, );
printf("%d: locked!\n", getpid()); pid = fork();
if (pid == ) {
lockf(fd, F_LOCK, );
printf("%d: locked!\n", getpid());
exit();
}
wait(NULL);
unlink(PATH);
exit();
}
执行结果:
Sangfor:aCMP/acmp-fefcfe3a1674 ~/test o ./a1.out
: locked!
这次我们没有对文件重新open,子进程就一直等在那里。完全符合我们的预期。这也印证了lockf的实现是内核中i-node相关的。
此外有一篇文章介绍建议性锁和强制性锁,这篇文章是以flock为例说明的,flock和lockf的加锁规则是一致的。需要了解加锁规则请参看:
强制性锁和建议锁
linux 文件锁flock,lockf,fcntl的更多相关文章
- linux文件锁flock【转】
转自: https://www.cnblogs.com/kex1n/p/7100107.html linux文件锁flock 在多个进程同时操作同一份文件的过程中,很容易导致文件中的数据混乱,需要 ...
- Linux文件锁flock
Linux文件锁flock 在多个进程同时操作同一份文件的过程中,很容易导致文件中的数据混乱,需要锁操作来保证数据的完整性,这里介绍的针对文件的锁,称之为“文件锁”-flock. flock,建议性锁 ...
- Linux文件锁学习-flock, lockf, fcntl
参考 linux中fcntl().lockf.flock的区别 这三个函数的作用都是给文件加锁,那它们有什么区别呢? 首先flock和fcntl是系统调用,而lockf是库函数.lockf实际上是f ...
- Linux 文件锁flock 实现两个进程相互监听存活状态
表头文件 #include<sys/file.h> 定义函数 int flock(int fd,int operation); 函数说明 flock()会依参数operation所指 ...
- Linux文件锁flock ,检测进程是否已经存在
在多个进程同时操作同一份文件的过程中,很容易导致文件中的数据混乱,需要锁操作来保证数据的完整性,这里介绍的针对文件的锁,称之为“文件锁”-flock. 头文件:#include<sys/fil ...
- 文件锁-fcntl flock lockf
这三个函数的作用都是给文件加锁,那它们有什么区别呢? 首先flock和fcntl是系统调用,而lockf是库函数.lockf实际上是fcntl的封装,所以lockf和fcntl的底层实现是一样的,对文 ...
- 每天进步一点点——Linux文件锁编程flock
转载请注明出处:http://blog.csdn.net/cywosp/article/details/30083015 1. 场景概述 在多线程开发中.相互排斥锁能够用于对临界资源的保护,防 ...
- php原子操作,文件锁flock,数据库事务
php原子操作,文件锁flock,数据库事务 php没有继承posix标准支持的unix锁,只封装了一个linux系统调用flock(信号量也能做成锁),按理也是可以使用锁机制的,虽然效率低一点.ph ...
- Linux文件锁【转】
本文转载自:http://blog.csdn.net/dragon_li_chen/article/details/17147911 一.文件锁的分类: 翻阅参考资料,你会发现文件锁可以进行很多的分类 ...
随机推荐
- 第七章·Logstash深入-收集NGINX日志
1.NGINX安装配置 源码安装nginx 因为资源问题,我们先将nginx安装在Logstash所在机器 #安装nginx依赖包 [root@elkstack03 ~]# yum install - ...
- AWK程序设计语言
一. AWK入门指南 Awk是一种便于使用且表达能力强的程序设计语言,可应用于各种计算和数据处理任务.本章是个入门指南,让你能够尽快地开始编写你自己的程序.第二章将描述整个语言,而剩下的章节将向你展示 ...
- 通过url下载文件到指定目录 java
import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io ...
- Liux chmod 给文件夹赋权限
777 最高权限 给文件夹及子文件夹赋权限 chmod -R 777 * 给单独文件赋权限 chmod -R 777 ./startup.sh
- php+memcache实现的网站在线人数统计
<?php $mc = new Memcache (); // 连接memcache $mc->connect ( ); // 获取 在线用户 IP 和 在线时间数据 $online_me ...
- 第十一章 前端开发-JavaScript
第十一章 前端开发-JavaScript 11.3.1 js引入方式 行内样式 <p id="" class="" style="" ...
- logback.xml 配置详解(转)
<?xml version="1.0" encoding="UTF-8"> <configuration> <!-- 设置控制台日 ...
- WPF显示数据库内容
https://www.bilibili.com/video/av45138636?from=search&seid=17612939715579515358 以后用到会详细总结.
- jmeter 5.0,http请求登录返回的cookie在头部处理方法
http登录之后返回的cookie在响应的头部,再次请求虽然加了cookie管理器,但是下一个请求调用响应是登陆失效,这里讲一下我的解决方法 1:在登录之后添加正则表达式,提取cookie 2:提取之 ...
- 【Python之路】特别篇--RabbitMQ
RabbitMQ 解释RabbitMQ,就不得不提到AMQP(Advanced Message Queuing Protocol)协议. AMQP协议是一种基于网络的消息传输协议,它能够在应用或组织之 ...