1.Linux 中的文件锁

Linux 支持的文件锁技术主要包括劝告锁(advisory lock)和强制锁(mandatory lock)这两种。此外,Linux 中还引入了两种强制锁的变种形式:共享模式强制锁(share-mode mandatory lock)和租借锁(lease)。

在 Linux 中,不论进程是在使用劝告锁还是强制锁,它都可以同时使用共享锁和排他锁(又称为读锁和写锁)。多个共享锁之间不会相互干扰,多个进程在同一时刻可以对同一个文件加共享锁。但是,如果一个进程对该文件加了排他锁,那么其他进程则无权再对该文件加共享锁或者排他锁,直到该排他锁被释放。所以,对于同一个文件来说,它可以同时拥有很多读者,但是在某一特定时刻,它只能拥有一个写者,它们之间的兼容关系如表所示。

锁间的兼容关系

是否满足请求
当前加上的锁
共享锁
排他锁
共享锁
排他锁

共享锁=读锁,排它锁=写锁

也就是说当前文件没有加锁时,此时共享锁和排他锁都能够加到此文件上

当前文件有共享锁时,此时只能在文件上加共享锁(同一个文件可以拥有很多读者),不能加排他锁

当前文件有排他锁时,不能在文件上继续加锁

进行对已加强制锁的文件进行操作时的行为

当前锁类型 阻塞读 阻塞写 非阻塞读 非阻塞写
读锁 正常读取数据 阻塞 正常读取数据 EAGAIN
写锁 阻塞 阻塞 EAGAIN EAGAIN

当前文件已经有一个读锁时,再加一个读锁(阻塞读,例如:fcntl(fd, F_SETLKW, &flock);非阻塞读:fcntl(fd, F_SETLK, &flock))是可以加上去的;如果再加一个写锁(阻塞写:导致阻塞;非阻塞写:返回errorno)

当文件有一个写锁时,同理。

文件中的每个字节在任一时刻只能拥有一种类型的锁:共享锁(读锁)、独占锁(写锁)或解锁。

2.实现文件锁

Linux可以通过这几种方式来实现文件锁功能:使用fcnt1系统调用和使用lockf调用以及flock。
我们将主要介绍fcnt1接口,因为它是最常使用的接口。lockf和fcnt1非常相似,在Linux中,它一般作为fcnt1的备选接口。但是,fcnt1和lockf的锁定机制不能同时工作:它们使用不同的底层实现,
因此决不要混合使用这两种类型的调用,而应坚持使用其中的一种。
fcntl不仅能锁整个文件,还能选择锁定这个文件的某一部分字节。
fcntl函数原型
int fcntl(int fildes, int command, ...);
fildes表示打开的文件描述符,command表示3个设置文件锁的选项
F_GETLK
F_SETLK
F_SETLKW
当使用这三个command的时候,第三个参数必须是一个指向flock结构的指针,所以实际的函数原型应为
int fcntl(int fildes, int command, struct flock *flock_structure);
struct flock(文件锁)结构依赖具体的实现,但它至少包含下述成员:
short l_type:取值定义在头文件fcnt1.h中:F_RDLCK(读锁)、F_UNLCK(解锁)、F_WRLCK(写锁)
short l_whence:取值必须是SEEK_SET、SEEK_CUR、SEEK_END(在头文件unistd.h中定义)中的一个。它们分别对应于文件头、当前位置和文件尾。
off_t l_start:相对于l_whence偏移的字节
off_t l_len:从l_start开始的字节数,为0表示文件末尾
pid_t l_pid:持有当前锁的进程pid
当把command设置为F_GETLK时,可以用flock_structure所描述的锁来测试fildes所代表的文件,看flock_structure锁描述的锁是否可以加到fildes所代表的文件上去。不可以加锁:把当前文件已经存在的锁写入flock_structure中,覆盖你开始设置的flock_structure;可以加锁:flock_structure的l_type变为F_UNLCK,并保持flock_structure中其他信息不变返回。(不会真正加锁,仅仅用来判断某个锁是否可以加上去,不能判断文件是否已经上锁)
例如:fcntl(fildes, F_GETLK, &flock_structure);
函数返回非-1表示调用成功(并不是说锁可以加上去),必须检查flock_structure结构的内容来判断其是否被修改过。因为l_pid的值被设置成持有锁的进程(如果有的话)的标识符,所以通过检查这个字段就可以很方便地判断出flock_structure结构是否被修改过(调用fcntl前,先把flock_structure的l_pid设置为-1(进程编号不会小于0),如果调用之后这个值改变了,说明是不能加锁的;也可以判断l_type,如果调用完后变成了F_UNLCK,那就说明可以加锁)。

command=F_SETLK时,对fildes指向的文件的某个区域加锁或解锁。加锁类型由l_type决定,区域由l_whence,l_start,l_len共同决定,这个函数立即返回成功(非-1值)或失败(-1)

command=F_SETLKW时,与上面的F_SETLK基本相同,只是在无法为文件添加锁时,函数将阻塞,直到可以添加锁或者获取到某个信号。

程序对某个文件拥有的所有锁都将在相应的文件描述符被关闭时自动清除。在程序结束时也会自动清除各种锁。

3.死锁

在讨论锁定时如果未提到死锁的危险,那么这个讨论就不能算是完整的。假设两个程序想要更新同一个文件。它们需要同时更新文件中的字节1和字节2。程序A选择首先更新字节2,然后再更新字节1。程序B则是先更新字节1,然后才是字节2。 两个程序同时启动。程序A锁定字节2,而程序B锁定字节1。然后程序A尝试锁定字节1,但因为这个字节已经被程序B锁定,所以程序A将在那里等待。接着程序B尝试锁定字节2,但因为这个字节已经被程序A锁定,所以程序B也将在那里等待。 这种两个程序都无法继续执行下去的情况,就被称为死锁(deadlock或deadly embrace)。这个问题在数据库应用程序中很常见,当许多用户频繁访问同一个数据时就很容易发生死锁。大多数的商业关系型数据库都能够检测到死锁并自动解开,但Linux内核不行。这时就需要采取一些外部干涉手段,例如强制终止其中一个程序来解决这个问题。 程序员必须对这种情况提高警惕。当有多个程序都在等待获得锁时,你就需要非常小心地考虑是否会发生死锁。在本例中,死锁是非常容易避免的:两个程序只需要使用相同的顺序来锁定它们需要的字节或锁定一个更大的区域即可。

Linux 2.6 中的文件锁:http://www.ibm.com/developerworks/cn/linux/l-cn-filelock/

fcntl函数:http://qcyhzwq001.lofter.com/tag/%E5%87%BD%E6%95%B0

获取锁定信息:http://docs.oracle.com/cd/E19253-01/819-7052/fileio-ex-1/index.html

记录上锁:http://www.cnblogs.com/siguoya/p/3512051.html

Linux文件锁和fcntl系统调用相关推荐

  1. Linux 文件锁 fcntl 函数详解

    Linux 文件锁 fcntl 函数详解 #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd); ...

  2. linux下阻塞的系统调用,Linux下socket设置为非阻塞方式和fcntl系统调用.pdf

    Linux 下 socket 设置为非阻塞方式和 fcntl 系统调用 [ 日期: 2011-04-16] 来源: Linux 社区 作者: Linux 用以下方法将 socket 设置为非阻塞方式 ...

  3. Linux文件锁内核VFS层源码实现讲解

    此文档主要介绍Linux内核FL_FLOCK和FL_POSIX两种类型的文件锁在VFS层的实现.对强制性锁和租约锁**(lease**)不做过多的讨论.基于的内核版本为3.10.0-862.el7.x ...

  4. Linux内核深入理解系统调用(3):open 系统调用实现以及资源限制(setrlimit/getrlimit/prlimit)

    Linux内核深入理解系统调用(3) open 系统调用实现以及资源限制(setrlimit/getrlimit/prlimit) rtoax 2021年3月 对原文进行了5.10.13的代码分析. ...

  5. 跟踪分析Linux内核5.0系统调用处理过程

    跟踪分析Linux内核5.0系统调用处理过程 学号384 原创作业转载请注明出处+中国科学技术大学孟宁老师的Linux操作系统分析 https://github.com/mengning/linuxk ...

  6. linux内核打开prntk,操作系统实验一向Linux内核增加一个系统调用.docx

    操作系统实验一: 向Linux内核增加一个系统调用 xx 711103xx 2012年3月18日 一.实验目的 通过实验,熟悉Linux操作系统的使用,掌握构建与启动Linux内核的方法:掌握用 户程 ...

  7. Linux下简单的系统调用

    原创 2017年03月17日 21:31:20 标签: linux / 嵌入式汇编 / 简单系统调用 杨金龙 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http:/ ...

  8. linux内核杂记(16)-系统调用(3)

    1.系统调用的2种使用方式: (1)靠C库支持,用户程序通过包含标准头文件并和C库链接,可使用系统调用 (2)调用库函数,再由库函数实际调用. 提示:如果你只写出系统调用,glibc库恐怕不提供支持. ...

  9. linux下阻塞的系统调用,Linux下文件的阻塞与非阻塞对部分系统调用的影响

    1.基本概念 所谓的阻塞,即内核在对文件操作I/O系统调用时,如果条件不满足(可能需要产生I/O),则内核会将该进程挂起.非阻塞则是发现条件不满足就会立即返回.此外需要注意的是非阻塞并不是轮询,不然就 ...

最新文章

  1. 基于 Nginx+lua+Memcache 实现灰度发布
  2. 撕起来了!谁说数据少就不能用深度学习?这锅俺不背!
  3. 关于JavaScript 数组 的一切
  4. 流浪地球与战狼2所反映的文化心态
  5. pandas基础(part2)--DataFrame
  6. php中怎么让主键自增长,在数据库设计中,无论如何也该设计一个自增ID字段作为主键吗?...
  7. Java 中的List动态转Map集合
  8. Open Live Writer测试
  9. matlab 滤波器设计 coe_一种半带滤波器的低功耗实现方法
  10. 163邮箱:退信代码(对照表) - 说明篇
  11. es6 Promise 的含义
  12. windows操作系统,python环境下django的自动安装
  13. 最小生成树(hdu1233还是畅通工程)
  14. WSO2 发布 WSO2Mobile 专注企业移动应用
  15. Eclipse中的Git使用之Branch创建,Merge
  16. Stanford机器学习---第三讲. 逻辑回归和过拟合问题的解决 logistic Regression Regularization
  17. python网络编程 赵宏_【干货收藏】Python面试指南大全
  18. java bytebuffer读取_Java NIO学习笔记之二-图解ByteBuffer
  19. 上帝为什么不直接把魔鬼撒但这等邪…
  20. js-通过audioContext实现3D音效

热门文章

  1. 北京工商大学计算机考研818真题,2018年北京工商大学818数据结构考研大纲
  2. MapReduce(分布式计算框架)
  3. 华为在线机试训练Python答案1-5题
  4. javaSE01_计算机常识_MarkDown语法
  5. 在win10+vs2019下对openmvg+openmvs的编译总结
  6. 电商edi增值电信许可证的必要性,edi电信经营许可证办理流程及条件
  7. Zabbix 集中监控系统
  8. 艾美捷ProSci丨ProSci 免疫检查点研究试剂
  9. iOS开发-fishhook交换NSLog函数实现
  10. 数据可视化(4)散点图及面积图