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的更多相关文章

  1. linux文件锁flock【转】

    转自: https://www.cnblogs.com/kex1n/p/7100107.html linux文件锁flock   在多个进程同时操作同一份文件的过程中,很容易导致文件中的数据混乱,需要 ...

  2. Linux文件锁flock

    Linux文件锁flock 在多个进程同时操作同一份文件的过程中,很容易导致文件中的数据混乱,需要锁操作来保证数据的完整性,这里介绍的针对文件的锁,称之为“文件锁”-flock. flock,建议性锁 ...

  3. Linux文件锁学习-flock, lockf, fcntl

    参考  linux中fcntl().lockf.flock的区别 这三个函数的作用都是给文件加锁,那它们有什么区别呢? 首先flock和fcntl是系统调用,而lockf是库函数.lockf实际上是f ...

  4. Linux 文件锁flock 实现两个进程相互监听存活状态

    表头文件  #include<sys/file.h> 定义函数  int flock(int fd,int operation); 函数说明  flock()会依参数operation所指 ...

  5. Linux文件锁flock ,检测进程是否已经存在

    在多个进程同时操作同一份文件的过程中,很容易导致文件中的数据混乱,需要锁操作来保证数据的完整性,这里介绍的针对文件的锁,称之为“文件锁”-flock.  头文件:#include<sys/fil ...

  6. 文件锁-fcntl flock lockf

    这三个函数的作用都是给文件加锁,那它们有什么区别呢? 首先flock和fcntl是系统调用,而lockf是库函数.lockf实际上是fcntl的封装,所以lockf和fcntl的底层实现是一样的,对文 ...

  7. 每天进步一点点——Linux文件锁编程flock

    转载请注明出处:http://blog.csdn.net/cywosp/article/details/30083015 1. 场景概述     在多线程开发中.相互排斥锁能够用于对临界资源的保护,防 ...

  8. php原子操作,文件锁flock,数据库事务

    php原子操作,文件锁flock,数据库事务 php没有继承posix标准支持的unix锁,只封装了一个linux系统调用flock(信号量也能做成锁),按理也是可以使用锁机制的,虽然效率低一点.ph ...

  9. Linux文件锁【转】

    本文转载自:http://blog.csdn.net/dragon_li_chen/article/details/17147911 一.文件锁的分类: 翻阅参考资料,你会发现文件锁可以进行很多的分类 ...

随机推荐

  1. 百度云直线在线解析+xdown

    一:在浏览器打开百度云分享链接(推荐Google)百度云分享的链接:https://pan.baidu.com/s/17YQ2x--kOAa_hpapaTcq8Q第二步:打开直线在线解析:https: ...

  2. 关于php 7.4编译安装

    一个不错的文章 https://hqidi.com/150.html 贴个地址就好啦, 借鉴了一把,很良心

  3. Java ==和equals的区别

    首先了解默认equals方法实现代码 public boolean equals(Object obj) { return (this == obj); } 1.== (1)对于基本数据类型的变量,& ...

  4. linux下安装google-chrome浏览器和chromedriver

    1.root用户下进入到etc/yum.repos.d目录下 [root@f7d6b9f2-1291-4d2f-8805-aef94deac9f7 yum.repos.d]# pwd cd /etc/ ...

  5. CH5105 Cookies饼干(线性DP)

    题意理解 圣诞老人共有\(M\)个饼干,准备全部分给\(N\)个孩子. 每个孩子有一个贪婪度,第 i 个孩子的贪婪度为 \(g[i]\). 如果有 \(a[i]\) 个孩子拿到的饼干数比第 \(i\) ...

  6. maven-war-plugin

    Name Type Since Description 默认值 cacheFile File 2.1-alpha-1 包含webapp结构的文件缓存 ${project.build.directory ...

  7. pod denied问题

    /Users/xxx/Library/Developer/Xcode/DerivedData/xxx-cdsvdpxrnyrnhshklcylefhdtghq/Build/Intermediates. ...

  8. openssh的服务端配置文件

    一.因为部分配置长时间不使用就忘了,为了方便查阅,我在这里检点写一些比较有用的ssh配置选项. PortListenAddress ip       #监听自己的哪个端口,默认是都监听的,如果指定了I ...

  9. Python3之Requests模块详解

    # 导入 Request模块 # 若本机无自带Request模块,可自行下载或者使用pip进行安装 # python版本Python3 import requests import json #### ...

  10. BZOJ 2219 数论之神 (CRT推论+BSGS+原根指标)

    看了Po神的题解一下子就懂了A了! 不过Po神的代码出锅了-solve中"d-temp"并没有什么用QwQQwQQwQ-应该把模数除以p^temp次方才行. 来自BZOJ讨论板的h ...