上午在看UNP卷二这一节的时候及其想睡觉,就草草了事,夜晚没有事情干,就来找找博客看看这两个锁到底是怎么回事吧!

参考文章:https://www.ibm.com/developerworks/cn/linux/l-cn-filelock/index.html

背景知识:在早期的 UNIX 系统,其只支持对整个文件进行加锁,因此无法运行数据库之类的程序,因为此类程序需要实现记录级的加锁。而在 System V Release 3 中,通过 fcntl 提供了记录级的加锁,此后发展成为 POSIX 标准的一部分。

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

在linux中,不论进程是在使用劝告锁还是强制锁,它都可以同时使用共享锁和独占锁(读锁和写锁),在同一时刻,可以有多个共享锁在一个文件中,但不能有独占锁;当有一个独占锁的时候,就不能有共享锁和其他独占锁。

劝告锁

有的也称建议性上锁。所谓建议性,我们这样想。就像红灯停绿灯行一样,我们把红绿灯当作一种建议锁,但其只是一种规则,还是会有人闯红的。

那我们的劝告锁也是这样。在上面我们介绍了关于共享锁和独占锁的一般规律,但是劝告锁的话,就是虽然设置了这个规定,但是他还是不能防止在一个文件有共享锁的时候,另一个独占锁还可以往文件写东西。当有一个独占锁的时候,还是可以有一个共享锁来读文件内容。

对于这一种锁来说,内核只提供加锁以及检测文件是否已经加锁的手段,但是内核并不参与锁的控制和协调。

劝告锁是一种协同工作的锁。它对于协作进程(cooperating processes)已经足够了。我们先来解释一下这个cooperating processes

它指的就是具有协作关系的进程:

某些进程为完成同一任务需要分工协作,由于合作的每一个进程都是独立地以不可预知的速度推进,这就需要相互协作的进程在某些协调点上协调各自的工作。当合作进程中的一个到达协调点后,在尚未得到其伙伴进程发来的消息或信号之前应阻塞自己,直到其他合作进程发来协调信号或消息后方被唤醒并继续执行。这种协作进程之间相互等待对方消息或信号的协调关系称为进程同步。

举两个例子:(1)我们可以同时在两个窗口中运行同一个命令,对同一个文件进行操作,那么这两个进程就是cooperating processes;(2)进程间的协作可以是双方不知道对方名字的间接协作 如:cat file| sort,那么cat和sort产生的进程就是使用了pipe的cooperating processes。

那在shell中协作进程是指一个shell命令的前面添加了coproc关键字的情形。

也就是说如果为协作进程的话,就像管道,它本身就会等待上一个的输出,所以说,对于协作进程来说劝告锁就够了。

在网络编程中守护程序的编写是协作进程的一个例子:这些程序访问诸如序列号之类的共享资源,而且都在系统管理员的控制之下。

下面是一个守护进程的程序,保证了其不管任何时候都只有一个副本。

介个程序一定要注意及时刷新缓冲区,另外也提醒我们把带有缓冲区的I/O,和不带缓冲区的I/O混用是一件很不好的编程行为!

//守护进程
#include<stdio.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<errno.h>
#include<unistd.h>#define write_lock(fd,offset,whence,len)\lock_reg(fd,F_SETLK,F_WRLCK,offset,whence,len)#define FILENAME "./2.txt"/*
守护进程维护一个只有一行的文本
其中含有它的进程ID,它打开一个文件然后请求整个文件的一个写入锁,
如果没有请求成功,则证明有一个副本在运行的*/int
lock_reg(int fd,int cmd,int type,off_t offset,int whence,off_t len)
{struct flock lock;lock.l_type = type;lock.l_start = offset;lock.l_whence = whence;lock.l_len = len;return (fcntl(fd,cmd,&lock));}int
main(int argc, char const *argv[])
{int fd;char line[1000];fd = open(FILENAME,O_RDWR | O_CREAT,644);if(write_lock(fd,0,SEEK_SET,0) < 0)//还要近一步根据错误原因来判断{if(errno == EACCES || errno == EAGAIN)printf("unable to lock %s,is %s already running?\n",//这里一定要加回车符刷新一下缓冲区,不然会什么消息都看不到FILENAME,argv[0]);elseprintf("unable to lock %s",FILENAME);}//判断完之后这几步不要忘记了//即没有一个守护进程的时候,要把含有自己PID的文本写进文件中snprintf(line,sizeof(line),"%ld\n",(long) getpid());ftruncate(fd,0);write(fd,line,strlen(line));//sizeof和strlen的区别也是需要注意的pause();}

运行结果如下:

强制锁

与劝告锁不同,强制锁是一种内核强制采用的文件锁,它是从 System V Release 3 开始引入的。每当有系统调用 open()、read() 以及write() 发生的时候,内核都要检查,以验证其操作不会干扰由某个进程持有的某个锁。

对于通常的阻塞式描述符,与某个强制性锁冲突的write或read讲把调用进程投入睡眠,直到该锁释放为止。对于非阻塞式描述符,将会返回一个EAGAIN错误。

然而,在有些应用中并不适合使用强制锁,所以索引节点结构中的 i_flags 字段中定义了一个标志位MS_MANDLOCK用于有选择地允许或者不允许对一个文件使用强制锁。在 super_block 结构中,也可以将 s_flags 这个标志为设置为1或者0,用以表示整个设备上的文件是否允许使用强制锁。

为对某个特定文件施行强制性上锁,应满足:
(1)组成员执行位必须关掉
(2)SGID位必须打开

$ chmod g+s test.txt
$ chmod g-x test.txt

但是理论上强制锁可以解决非协作进程的问题,但是任何read和write调用都将阻塞进程本身,直到该文件的锁被释放为止,不幸的是,定时问题相当复杂。

共享模式锁

共享模式强制锁可以用于某些私有网络文件系统,如果某个文件被加上了共享模式强制锁,那么其他进程打开该文件的时候不能与该文件的共享模式强制锁所设置的访问模式相冲突。但是由于可移植性不好,因此并不建议使用这种锁。

租借锁

采用强制锁之后,如果一个进程对某个文件拥有写锁,只要它不释放这个锁,就会导致访问该文件的其他进程全部被阻塞或不断失败重试;即使该进程只拥有读锁,也会造成后续更新该文件的进程的阻塞。为了解决这个问题,Linux 中采用了一种新型的租借锁。

当进程尝试打开一个被租借锁保护的文件时,该进程会被阻塞,同时,在一定时间内拥有该文件租借锁的进程会收到一个信号。收到信号之后,拥有该文件租借锁的进程会首先更新文件,从而保证了文件内容的一致性,接着,该进程释放这个租借锁。如果拥有租借锁的进程在一定的时间间隔内没有完成工作,内核就会自动删除这个租借锁或者将该锁进行降级,从而允许被阻塞的进程继续工作。

系统默认的这段间隔时间是 45 秒钟,定义如下:

 int lease_break_time = 45;

这个参数可以通过修改 /proc/sys/fs/lease-break-time 进行调节(当然,/proc/sys/fs/leases-enable 必须为 1 才行)。

linux中的文件锁(劝告性上锁和强制性上锁)相关推荐

  1. Linux中POSIX文件锁的实现

    我试图通过个人的理解方式讲解Linux文件锁的实现,使用的内核版本是3.13.0. POSIX文件锁简介 先简单说下什么是文件锁. Linux文件锁有两种:协同锁(有些成为建议锁)和强制锁.Linux ...

  2. Linux 中的文件锁

    参考资料: https://www.ibm.com/developerworks/cn/linux/l-cn-filelock/index.html 转载于:https://www.cnblogs.c ...

  3. linux中lockf的例子,小何讲Linux: 文件锁及其实例

    1.  文件锁基本概念 Linux中软件.硬件资源都是文件(一切皆文件),文件在多用户环境中是可共享的. 文件锁是用于解决资源的共享使用的一种机制:当多个用户需要共享一个文件时,Linux通常采用的方 ...

  4. linux中fcntl()、lockf、flock的区别

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

  5. linux中常用的60个命令及作用详解

    Linux 必学的 60 个命令 Linux 提供了大量的命令,利用它可以有效地完成大量的工作,如磁盘操作.文件存 取.目录操作.进程管理.文件权限设定等.所以,在 Linux 系统上工作离不开使用系 ...

  6. linux 中的中断处理

    谈谈对中断的理解 1.裸板中断处理过程 中断属于异常的一种 它是计算机中处理异步事件的重要机制1.1 中断的触发中断源级配置中断的触发方式 上升沿 下降沿 高 低触发中断使能 (监测到中断信号之后,能 ...

  7. linux shell之文件锁

    2019独角兽企业重金招聘Python工程师标准>>> 经常在 shell 脚本里要阻止其它进程,比如 msmtp 自带的mail queue 脚本,这个脚本的互斥做法是不正确的,下 ...

  8. Redis+在Linux中安装使用

    Redis+在Linux中安装使用 一.安装 (一).上传redis安装包 (二).进入到rpmgcc文件下 (三).解压redis-3.2.5.tar.gz (四).启动redis 二.Redis概 ...

  9. Linux中_Ubuntu上_使用命令总结整理_02

    文章目录 目录: 1.操作系统操作 1.Linux 基础 2.系统信息 3.系统负载 -- top 4.程序开机自启动服务配置 5.重定向_管道_流 6.终端其他命令 2.文件与目录操作 1.文件和目 ...

最新文章

  1. 如何生成表_SPSS简单操作 | 如何生成交叉表?
  2. C++中对Mysql的操作函数可以参考以下blog中的内容
  3. java如何改注释_关于Java:更改字符串值的注释
  4. 【转】C#中[STAThread]的作用
  5. 【转】新.Net开发必备工具详解之Snippet Compiler。
  6. 如何打造数据驱动型企业
  7. opencart 添加新模型
  8. 使用ResultReceiver的Android IntentService
  9. java class 文件
  10. Linux 内存泄漏检查工具 valgrind
  11. c语言星钻图形的输出
  12. RQNOJ愚蠢的矿工
  13. 反爬虫绕过初级——添加http header和gzip解压处理
  14. PostScirpt打印机驱动程序
  15. 从裸机到嵌入式Linux—总纲
  16. android高仿ios键盘,iOS仿工商银行app自定义键盘
  17. 语音编码标准(G.711 G.723 G.726 G.729 iLBC) .
  18. 2022-01-17 opencv-3.4.1 zlib.h: No such file or direc
  19. webstorm/idea license server
  20. 一种基于Android、iOS平台的移动端车牌识别方法,能够在复杂背景下迅速识别多种车牌

热门文章

  1. EOF和BOF的理解
  2. RGBA颜色与兼容性的半透明背景色
  3. Tomcat介绍及安装JDK1.8
  4. android studio aapt err,Android Studio 3.0,AAPT2编译失败 – 资源文件中的dimen无效
  5. 1256:献给阿尔吉侬的花束(BFS)
  6. 软件测试的分类(二)
  7. ubuntu 可执行简单脚本编写
  8. 菜鸟在 windows 下 python 中安装 jupyter 踩坑要点 、被神化的 VsCode
  9. 联想拯救者 Y7000P 2020和Y7000 2020的区别 哪个好
  10. Chrome| 汇总