Linux编程中的文件锁之flock

2024-01-19 11:32
文章标签 linux 编程 flock

本文主要是介绍Linux编程中的文件锁之flock,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转载请说明出处:http://blog.csdn.net/cywosp/article/details/30083015


1. 场景概述
     在多个进程同时操作同一份文件的过程中,很容易导致文件中的数据混乱,需要锁操作来保证数据的完整性,这里介绍的针对文件的锁,称之为“文件锁”-flock。
    在多线程开发中,互斥锁可以用于对临界资源的保护,防止数据的不一致,这是最为普遍的使用方法。那在多进程中如何处理文件之间的同步呢?我们看看下面的图:
                                     
图中所示的是两个进程在无同步的情况下同时更新同一个文件的过程,其主要的操作是:
1. 从文件中读取序号。
2. 使用这个序号完成应用程序定义的任务。
3. 递增这个序号并将其写回文件中。
从图中可得知两个进程读取分别增加了所读取到的序号,并写回到了文件中,但是如果有相互互斥的话,最后的值应该是1002,而不是所示的1001。为了防止出现这种情况,Linux提供了flock(对整个文件加锁)、fcntl(对整个文件区域加锁)两个函数来做进程间的文件同步。同时也可以使用信号量来完成所需的同步,但通常使用文件锁会更好一些,因为内核能够自动将锁与文件关联起来。

2. flock()
    flock函数的声明如下
#include <sys/file.h>
int flock (intfdint operation);// Returns 0 on success, or -1 on error

    fcntl()函数提供了比该函数更为强大的功能,并且所拥有的功能也覆盖了flock()所拥有的功能,但是在某些应用中任然使用着flock()函数,并且在继承和锁释放方面的一些语义 中flock()与fcntl()还是有所不同的。
    flock()系统调用是在整个文件中加锁,通过对传入的fd所指向的文件进行操作,然后在通过operation参数所设置的值来确定做什么样的操作。operation可以赋如下值:
                
LOCK_SH,共享锁,多个进程可以使用同一把锁,常被用作读共享锁;
LOCK_EX,排他锁(互斥锁),同时只允许一个进程使用,常被用作写锁;
LOCK_UN,释放锁;

    在默认情况下,如果另一个进程已经持有了文件上的一个不兼容的锁,那么flock()会阻塞。如果需要防止这种情况的出现,可以在operation参数中对这些值取OR(|)。在这种情况下,如果一个进程已经持有了文件上的一个不兼容锁,那么flock()不会阻塞,相反,它会返回-1,并将errno设置成EWOULDBLOCK。即提供两种工作模式:阻塞与非阻塞类型。

服务会阻塞等待直到锁被释放:
flock(lockfd,LOCK_EX)
现文件已经被锁住时服务会返回错误发:
ret  = flock(lockfd,LOCK_EX|LOCK_NB)
同时ret = -1, errno = EWOULDBLOCK 

    任意数量的进程可同时持有一个文件上的共享锁,但任意时刻只能有一个进程能够持有一个文件上的互斥锁,(这有点类似读写锁)。      
    无论程序以什么模式打开了文件(读、写或者读写),该文件上都可以放置一把共享锁或互斥锁。在实际操作过程中,参数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()放置的锁。
注释:在默认情况下,文件锁是劝告式的,是建议性锁,不具备强制性。这表示一个进程可以简单地忽略另一个进程在文件上放置的锁。一个进程使用flock将文件锁住,另一个进程可以直接操作正在被锁的文件,修改文件中的数据,原因在于flock只是用于检测文件是否被加锁,针对文件已经被加锁,另一个进程写入数据的情况,内核不会阻止这个进程的写入操作,也就是建议性锁的内核处理策略。要使得劝告式加锁模型能够正常工作,所有访问文件的进程都必须要配合,即在执行文件IO之前先放置一把锁

这篇关于Linux编程中的文件锁之flock的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/622282

相关文章

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

Linux系统中卸载与安装JDK的详细教程

《Linux系统中卸载与安装JDK的详细教程》本文详细介绍了如何在Linux系统中通过Xshell和Xftp工具连接与传输文件,然后进行JDK的安装与卸载,安装步骤包括连接Linux、传输JDK安装包... 目录1、卸载1.1 linux删除自带的JDK1.2 Linux上卸载自己安装的JDK2、安装2.1

Java并发编程必备之Synchronized关键字深入解析

《Java并发编程必备之Synchronized关键字深入解析》本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种... 目录一、前言二、Synchronized关键字2.1 Synchronized的特性1. 互斥2.

Linux卸载自带jdk并安装新jdk版本的图文教程

《Linux卸载自带jdk并安装新jdk版本的图文教程》在Linux系统中,有时需要卸载预装的OpenJDK并安装特定版本的JDK,例如JDK1.8,所以本文给大家详细介绍了Linux卸载自带jdk并... 目录Ⅰ、卸载自带jdkⅡ、安装新版jdkⅠ、卸载自带jdk1、输入命令查看旧jdkrpm -qa

Linux samba共享慢的原因及解决方案

《Linuxsamba共享慢的原因及解决方案》:本文主要介绍Linuxsamba共享慢的原因及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux samba共享慢原因及解决问题表现原因解决办法总结Linandroidux samba共享慢原因及解决

新特性抢先看! Ubuntu 25.04 Beta 发布:Linux 6.14 内核

《新特性抢先看!Ubuntu25.04Beta发布:Linux6.14内核》Canonical公司近日发布了Ubuntu25.04Beta版,这一版本被赋予了一个活泼的代号——“Plu... Canonical 昨日(3 月 27 日)放出了 Beta 版 Ubuntu 25.04 系统镜像,代号“Pluc

Linux安装MySQL的教程

《Linux安装MySQL的教程》:本文主要介绍Linux安装MySQL的教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux安装mysql1.Mysql官网2.我的存放路径3.解压mysql文件到当前目录4.重命名一下5.创建mysql用户组和用户并修

Linux上设置Ollama服务配置(常用环境变量)

《Linux上设置Ollama服务配置(常用环境变量)》本文主要介绍了Linux上设置Ollama服务配置(常用环境变量),Ollama提供了多种环境变量供配置,如调试模式、模型目录等,下面就来介绍一... 目录在 linux 上设置环境变量配置 OllamPOgxSRJfa手动安装安装特定版本查看日志在