Linux编程中的文件锁之flock

2023-05-16

1. 场景概述

    在多线程开发中,互斥锁可以用于对临界资源的保护,防止数据的不一致,这是最为普遍的使用方法。那在多进程中如何处理文件之间的同步呢?我们看看下面的图:
                                     
图中所示的是两个进程在无同步的情况下同时更新同一个文件的过程,其主要的操作是:
1. 从文件中读取序号。
2. 使用这个序号完成应用程序定义的任务。
3. 递增这个序号并将其写回文件中。
从图中可得知两个进程读取分别增加了所读取到的序号,并写回到了文件中,但是如果有相互互斥的话,最后的值应该是1002,而不是所示的1001。为了防止出现这种情况,Linux提供了flock(对整个文件加锁)、fcntl(对整个文件区域加锁)两个函数来做进程间的文件同步。同时也可以使用信号量来完成所需的同步,但通常使用文件锁会更好一些,因为内核能够自动将锁与文件关联起来。
2. flock()
    flock的声明如下
#include <sys/file.h>
// Returns 0 on success, or -1 on error
int flock (intfdint operation);
    fcntl()函数提供了比该函数更为强大的功能,并且所拥有的功能也覆盖了flock()所拥有的功能,但是在某些应用中任然使用着flock()函数,并且在继承和锁释放方面的一些语义 中flock()与fcntl()还是有所不同的。
    flock()系统调用是在整个文件中加锁,通过对传入的fd所指向的文件进行操作,然后在通过operation参数所设置的值来确定做什么样的操作。operation可以赋如下值:
                
    在默认情况下,如果另一个进程已经持有了文件上的一个不兼容的锁,那么flock()会阻塞。如果需要防止这种情况的出现,可以在operation参数中对这些值取OR(|)。在这种情况下,如果一个进程已经持有了文件上的一个不兼容锁,那么flock()就会阻塞,相反,它会返回-1,并将errno设置成EWOULDBLOCK。
    任意数量的进程可同时持有一个文件上的共享锁,但子任意时刻只能有一个进程能够持有一个文件上的互斥锁,(这有点类似读写锁)。下图是进程A先设置了锁,进程B后设置锁的支持情况:
                
无论程序以什么模式打开了文件(读、写或者读写),该文件上都可以放置一把共享锁或互斥锁。在实际操作过程中,参数operation可以指定对应的值将共享锁转换成互斥锁(反之亦然)。将一个共享锁转换成互斥锁,如果另一个进程要获取该文件的共享锁则会阻塞,除非operation参数指定了LOCK_NB标记,即:(LOCK_SH | LOCK_NB)。锁的转换过程不是一个原子操作,在转换的过程中首先会删除既有的锁,然后创建新锁。
3. 锁继承与释放的语义
    flock()根据调用时operation参数传入LOCK_UN的值来释放一个文件锁。此外,锁会在相应的文件描述符被关闭之后自动释放。同时,当一个文件描述符被复制时(dup()、dup2()、或一个fcntl() F_DUPFD操作),新的文件描述符会引用同一个文件锁。
flock(fd, LOCK_EX);
new_fd = dup(fd);
flock(new_fd, LOCK_UN);
这段代码先在fd上设置一个互斥锁,然后通过fd创建一个指向相同文件的新文件描述符new_fd,最后通过new_fd来解锁。从而我们可以得知新的文件描述符指向了同一个锁。所以,如果通过一个特定的文件描述符获取了一个锁并且创建了该描述符的一个或多个副本,那么,如果不显示的调用一个解锁操作,只有当文件描述符副本都被关闭了之后锁才会被释放。
    由上我们可以推出,如果使用fork()创建一个子进程,子进程会复制父进程中的所有描述符,从而使得它们也会指向同一个文件锁。例如下面的代码会导致一个子进程删除一个父进程的锁:
flock (fd, LOCK_EX);
if (0 == fork ()) {
    flock (fd, LOCK_UN);
}
所以,有时候可以利用这些语义来将一个文件锁从父进程传输到子进程:在fork()之后,父进程关闭其文件描述符,然后锁就只在子进程的控制之下了。通过fork()创建的锁在exec()中会得以保留(除非在文件描述符上设置了close-on-exec标记并且该文件描述符是最后一个引用底层的打开文件描述的描述符)。
    如果程序中使用open()来获取第二个引用同一个文件的描述符,那么,flock()会将其视为不同的文件描述符。如下代码会在第二个flock()上阻塞。
fd1 = open ("test.txt", O_RDWD);
fd2 = open ("test.txt", O_RDWD);
flock (fd1, LOCK_EX);
flock (fd2, LOCK_EX);
4. flock()的限制
flock()放置的锁有如下限制
  • 只能对整个文件进行加锁。这种粗粒度的加锁会限制协作进程间的并发。假如存在多个进程,其中各个进程都想同时访问同一个文件的不同部分。
  • 通过flock()只能放置劝告式锁。
  • 很多NFS实现不识别flock()放置的锁。
注释:在默认情况下,文件锁是劝告式的,这表示一个进程可以简单地忽略另一个进程在文件上放置的锁。要使得劝告式加锁模型能够正常工作,所有访问文件的进程都必须要配合,即在执行文件IO之前先放置一把锁。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux编程中的文件锁之flock 的相关文章

随机推荐

  • VS2017 C++error "cout": 不是"std"的成员,或者cout”: 未声明的标识符

    include pch h include iostream 原因是两个顺序写反了
  • STM32f103***烧写程序后使用STLINK V2无法连接芯片

    STM32f103 烧写程序后使用STLINK V2无法连接芯片 解决办法 xff1a 可以采用先按住RESET键点击下载后迅速松开RESET键就能下载程序了
  • VNCview的复制粘贴剪贴板共享

    autocutsel命令可以实现在CTRL 43 C和CTRL 43 V的复制粘贴 鼠标copy和paste也是可以的 autocutsel f 可以放入后台 更方便 安装 apt install autocutsel
  • 学习笔记tasksel(失败)-- 换用VNC完成

    开始学习时在云上申请了个服务器 xff0c 创建docker后 使用了一个docker pull ubuntu后准备装个图形界面 xff0c 作为代码阅读的环境 xff0c 因此使用tasksel来进行图形化界面安装 学习总结 xff1a
  • Centos7 k8s v1.5.2二进制部署安装-网络插件Flannel的安装

    一 安装部署网络插件 1 概念 kubeenetes设计了网络模型 xff0c 但是却将她得实现交给了网络插件 xff0c CNI网络插件最主要得功能就是实现POD资源能够跨宿主机进行通信 常见得CNI网络插件 xff1a Flannel
  • linux系统中重启网卡后网络不通(NetworkManager篇)

    个人博客 xff1a https 5mr xyz 一 故障现象 RHEL7 6系统 xff0c 使用nmcli绑定双网卡后 xff0c 再使用以下命令重启network服务后主机网络异常 xff0c 导致无法通过ssh远程登录系统 syst
  • Windows系统设置多用户同时远程登录

    个人博客 xff1a https 5mr xyz 一 在键盘上按Win 43 R键 也可以在开始菜单右键然后选择运行 xff0c 在运行的输入框里面输入 34 gpedit msc 34 命令 然后点击确定 二 在 计算机组策略 中依次展开
  • 在shell中把ls的输出存进一个数组变量中

    将ls的输出存到filelist数组中 xff1a c 61 0 for file in 96 ls 96 do filelist c 61 file c 43 43 done 或者 set a myfiles index 61 0 for
  • linux系统操作系统网卡漂移解决方案及问题原因

    个人博客 xff1a https 5mr xyz 一 问题描述 公司有100 150台服务器安装RHEL7 4 amp 中标麒麟7 4系统 xff0c 为方便编辑配置网卡 xff0c 使用脚本方式配置为biosname 61 0 xff0c
  • 内核报错kernel:NMI watchdog: BUG: soft lockup - CPU#1

    个人博客 xff1a https 5mr xyz 1 现象描述 系统管理员电话通知 xff0c 描述为一台服务器突然无法ssh连接 xff0c 登录服务器带外IP地址并进入远程控制台界面后 xff0c 提示Authentication er
  • Linux ls 命令提示 Input/output error

    个人博客 xff1a https 5mr xyz 一 问题描述 某一台跑批服务器硬盘无法正常读写 xff0c 提示input output error xff0c 服务器每天均需使用 xff0c 询问情况后发现服务器首先为硬盘故障 xff0
  • storcli工具的使用方法

    个人博客 xff1a https 5mr xyz 常用命令 xff1a xff08 c代表Controller xff0c e代表Enclosure xff0c s代表Slot或PD xff0c v代表ld xff09 opt MegaRA
  • xshell 连接报错 Disconnected from remote host

    个人博客 xff1a https 5mr xyz xshell连接报错 解决方法 1 登陆带外管理口远程控制台 2 查看 Var empty的属主属组和权限 xff0c empty权限需为755 3 Chmod 777 R var后导致ss
  • IPMI管理工具使用方法

    个人博客 xff1a https 5mr xyz 前言 最近需要对多台服务进行控制 xff0c 通过服务器的 BMC 控制台去控制太麻烦 xff0c 服务器刚好支持 IPMI 协议 xff0c 这里记录下常用的几条命令备忘 什么是 IPMI
  • k8s-cka考试题库

    个人博客 xff1a https 5mr xyz 本次测试的所有问题都必须在指定的cluster配置环境中完成 为尽量减少切换 xff0c 系统已对问题进行分组 xff0c 同一cluster内的所有问题将连续显示 开启TAB补全 做题前先
  • Segment Routing—BGP-LS

    BGP LS概况 BGP LS是学习多个IGP区域和区域拓扑的首选机制 BGP LS使用BGP xff0c 以可扩展的方式分发网络信息 重要的是 xff0c BGP LS还承载了IGP没有分发的信息 xff08 例如BGP对等体互联链路 x
  • OVN实验----L3互通

    概述 在L2互通基础上 xff0c 完成跨网段互访 物理拓扑 如上一个实验OVN实验 L2互通 逻辑拓扑 按照上个实验OVN实验 L2互通 的操作方式 xff0c 再配置一组容器blue xff0c 网段192 168 2 0 24 配置完
  • OVN实验----NAT

    概述 在L2互通 L3互通实验基础上通过NAT实现访问公网 架构图如下 xff0c 这里两台逻辑路由器LR1和GLR是通过一台逻辑交换机LSjoin互连的 xff0c GLR和物理网络设备通过LSlocal相连 物理拓扑 如上一个实验OVN
  • java环境变量配置好之后,cmd命令行javac为什么还是无效

    把cmd命令行关闭重启一下就好了 备注 xff1a jdk5 0之后 xff0c classpath不需要配置
  • Linux编程中的文件锁之flock

    1 场景概述 在多线程开发中 xff0c 互斥锁可以用于对临界资源的保护 xff0c 防止数据的不一致 xff0c 这是最为普遍的使用方法 那在多进程中如何处理文件之间的同步呢 xff1f 我们看看下面的图 xff1a 图中所示的是两个进程