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 一.文件锁的分类: 翻阅参考资料,你会发现文件锁可以进行很多的分类 ...
随机推荐
- 如何使用ProcessOn制作思维导图
新建一张思维导图之后你是不是有点茫然? 不是因为脑海里没思路,而是不知道怎么把脑海里的思路呈现出来?看到一个孤零零的中心主题和看起来有些简单的页面一时间有点无所适从? 很多人觉得思维导图好看但学起来难 ...
- Python爬虫解析htm时lxml的HtmlElement对象获取和设置inner html方法
Python的lxml是一个相当强悍的解析html.XML的模块,最新版本支持的python版本从2.6到3.6,是写爬虫的必备利器.它基于C语言库libxml2 和 libxslt,进行了Pytho ...
- [AWS - EC2] 如何向 Amazon Linux 2 实例传输文件,下载文件。How to send/ download files from Amazon Linux 2 Instance
1. 需要: 安装 WinSCP 2. 需要: PuTTY 生成的ppk格式密钥, 没有的话请移步此文章,完成1, 2, 3步即可. 3. 打开 WinSCP , 如果提示已经有PuTTY配置是否导入 ...
- zoj 4122 Triangle City 2019山东省赛J题
题目链接 题意: 给出一个无向图,类似三角形的样子,然后给出边的权值,问找一条从第一个点到最后一个点的路径,要求每一条边只能走一次,并且权值和最大,点可以重复走. 思路: 首先观察这个图可以发现,所有 ...
- Python——变量的作用域
原创声明:本文系博主原创文章,转载及引用请注明出处. 1. 在编程语言中,变量都有一定的作用域,用来限定其生命周期,且不同类型的变量作用域不同. 在Python中解释器引用变量的顺序(优先级)为:当前 ...
- JavaScript入门学习之二——函数
在前一章中讲了JavaScript的入门语法,在这一章要看看函数的使用. 函数的定义 JavaScript中的函数和Python中的非常类似,只不过定义的方式有些不同,下面看看是怎么定义的 //定义普 ...
- Maven编译
多模块 只有需要编译成jar的模块才设置build <build> <plugins> <plugin> <groupId>org.springfram ...
- 最简单之安装JDK
参考:https://www.cnblogs.com/lizhewei/p/11181082.html 1,百度搜索jdk 2,官网下载 jdk-8u161-linux-x64.rpm 或者jdk-8 ...
- Python之windows锁屏
简单粗暴,三行代码搞定 from ctypes import * user32 = windll.LoadLibrary('user32.dll') user32.LockWorkStation() ...
- ant-design-vue 修改组件样式
/deep/ .ant-input { border-radius: 50px; }