文件锁的读锁和写锁

对文件加锁时可以加两种锁,分别是“读文件锁”和“写文件锁”,简称读锁和写锁。

读锁、写锁之间关系

  1. 读锁和读锁共享:可以重复加读锁,别人加了读锁在没有解锁之前,我依然可以加读锁,这就是共享。
  2. 读锁和写锁互斥:别人加了读锁没解锁前,加写锁会失败,反过来也是如此。
    • 加锁失败后两种处理方式:

      • 阻塞,直到别人解锁然后加锁成功为止。
      • 出错返回,不阻塞
  3. 写锁与写锁互斥:别人加了写锁在没有解锁前,不能加写锁,加写锁会失败。
    • 加锁失败后两种处理方式:

      • 阻塞,直到别人解锁然后加锁成功为止
      • 出错返回,不阻塞

文件的加锁方式

  1. 对整个文件的内容加锁
    对整个文件加锁是最常用的文件加锁方式。
    当你整个文件加锁时,如果文件的长度因为写入新数据或者截短而发生了变化,加锁内容长度会自动变化,保证对内容变化着的整个文件加锁。

  2. 对文件某部分内容加锁

    不过一般来说,对多少内容加锁,就对多少内容解锁。如果你是对整个文件加锁,就将整个文件解锁。

    但是实际上加锁和实际解锁的长度不相同,比如我对1000个字节的内容加了锁,但是只对其中的100字节解锁,不过这种情况用的少,知道怎么回事即可。

    怎么实现文件的整个加锁和区域解锁呢?

    后面再说

再看看fcntl的函数原型

int fcntl(int fd, int cmd, ... /* struct flock *flockptr */ );

第三个参数是...,fcntl函数是一个变参函数,第三个参数用不到时就不写

  1. 功能
    fcntl函数有多种功能,我们这里主要介绍实现文件锁的功能,当cmd被设置的是与文件锁相关的宏时,fcntl就是用来实现文件锁。
  2. 参数
    • fd:文件描述符,指向所需要被加锁的文件
    • cmd:实现文件锁时,cmd有三种设置,F_GETLK,F_SETLK和F_SETLKW含义如下:
      1. F_GETLK
        从内核获取文件锁的信息,将其保存到第三个参数,第三个参数struct flock *flockptr,我们这里是要设置文件锁,而不是获取已有的文件锁信息,我们这里用不到这个宏。
      2. F_SETLK
        设置第三个参数所代表的文件锁,而且设置的是非阻塞文件锁,也就是如果加锁失败不会阻塞。也就是说加锁失败后如果不想阻塞的话,就由F_SETLK宏来设置。
        此时,需要用到第三个参数:struct flock *flockptr;
        使用举例:

        1. 第一步:定义一个struct flock flockptr结构体变量(这个结构体变量就是文件锁)。
        2. 第二步:设置flockptr的成员,表示你想设置怎样的文件锁
        3. 第三步:通过第三个参数,将设置好的flockptr的地址传递给fcntl,设置你想要的文件锁
      3. F_SETLKW
        F_SETLKW一样,只不过设置的是阻塞文件锁,也就是说加锁不成功的话就阻塞,是由F_SETLKW宏来决定的。
  3. int fcntl(int fd, int cmd, ... /* struct flock *flockptr */ );
    • 第三个参数

      • 第三个参数设置为什么视情况而定,如果fcntl用于实现文件锁的话,第三个参数为struct flock *flockptr,flockptr代表的就是文件锁。
      • 对flockptr的成员设置为特定的值,就可以将文件锁设置为你想要的锁。
      • struct flock结构体如下:
         struct flock {...short l_type;    /* Type of lock: F_RDLCK, F_WRLCK, F_UNLCK */short l_whence;  /* How to interpret l_start: SEEK_SET, SEEK_CUR, SEEK_END */off_t l_start;   /* Starting offset for lock */off_t l_len;     /* Number of bytes to lock */pid_t l_pid;     /* PID of process blocking our lock(set by F_GETLK and F_OFD_GETLK) */...
        };

成员说明:

  • l_type:锁类型

    • F_RDLCK:读锁(或称共享锁)
    • F_WRLCK:写锁
    • F_UNLCK:解锁
  • l_whence:加锁位置粗定位,设置同lseek的whence

    • SEEK_SET:文件开始处
    • SEEK_CUR:文件当前位置处
    • SEEK_END:文件末尾位置处
    • l_whence这个与lseek函数的whence是一个含义
  • l_start:精定位,相对于l_whence的偏移,与lseek的offset的含义完全一致
    通过l_whence和l_start的值,就可以用来指定从文件的什么位置开始加锁,不过一般来说,我们会将l_whence指定为SEEK_SET,l_start指定为0,表示从整个文件头上开始加锁。

  • l_len:从l_whence和l_start所指定的起始地点算起,需要对文件多长的内容加锁。

    如果 l_len被设置0,表示一直加锁到文件结尾,如果文件长度时变化的,将自动调整加锁的末尾位置

    l_whence和l_start设置为SEEK_SET和0,然后再将l_len设置为0,就表示从文件加锁到文件末尾,其实就是对整个文件加锁。

    如果只是对文件中间的某段加锁,这只是区域加锁,加区域锁时可以给文件n多个的独立区域加锁。

  • l_pid:当前正加锁进程的PID

代码演示

使用文件锁的互斥操作,解决父子进程向同一文件写"hello",“world\n”时,hello hello world相连的问题。

头文件,学到了封装函数的思想,尤其是使用宏来实现不同类型的文件锁

/* Too many parameters ,Different types of locks* Write dead!!!!!!!!!* */
/* Set non blocking write lock */
#define SET_WRFLCK(fd, l_whence, l_start, l_len) \set_filelock(fd, F_SETLK, F_WRLCK, l_whence, l_start, l_len)/* Set blocking write lock */
#define SET_WRFLCKW(fd, l_whence, l_start, l_len) \set_filelock(fd, F_SETLKW, F_WRLCK, l_whence, l_start, l_len)/* Set blocking read lock */
#define SET_RDFLCKW(fd, l_whence, l_start, l_len) \set_filelock(fd, F_SETLKW, F_RDLCK, l_whence, l_start, l_len)/* Set nonblocking read lock */
#define SET_RDFLCK(fd, l_whence, l_start, l_len) \set_filelock(fd, F_SETLK, F_RDLCK, l_whence, l_start, l_len)/* Unlock */
#define SET_UNFLCK(fd, l_whence, l_start, l_len) \set_filelock(fd, F_SETLK, F_UNLCK, l_whence, l_start, l_len)/*Package and set the locking function* */
static void set_filelock(int fd, int ifwait, short l_type, short l_whence, off_t l_start, short l_len)
{int ret = 0;struct flock flock;flock.l_type = l_type;flock.l_whence = l_whence;flock.l_start = l_start;flock.l_len = l_len;ret = fcntl(fd, ifwait, &flock);if (ret == -1){perror("fcntl");exit(EXIT_FAILURE);}
}
int main(int argc, char *argv[])
{int fd = 0;int ret = 0;fd = open("./hello", O_RDWR|O_CREAT|O_TRUNC, 0664);if (fd == -1)  print_err("./hello", __LINE__, errno); ret = fork();if (ret > 0){while(1){SET_WRFLCKW(fd, SEEK_SET, 0, 0);write(fd, "hello ", 6);write(fd, "world\n", 6);SET_UNFLCK(fd, SEEK_SET, 0, 0);}}else if (ret == 0){while(1){SET_WRFLCKW(fd, SEEK_SET, 0, 0);write(fd, "hello ", 6);write(fd, "world\n", 6);SET_UNFLCK(fd, SEEK_SET, 0, 0);}}return 0;
}

在hello文件里面使用/hello hello没找到文本内容说明成功了。

对于fcntl的认识不仅仅可以追加改变文件标志,还可以实现文件锁的功能

文件锁(二)——文件锁的读锁和写锁相关推荐

  1. 文件锁(三)——文件锁的原理

    文件锁的原理 理解了文件锁的原理后,就可以理解为什么文件锁可以实现互斥与共享了. 若A进程与B进程同时打开同一个文件,他们使用同一个文件表,使用同一个V节点,V节点指向hello这个文件,里面有一个锁 ...

  2. mysql的锁机制(读锁,写锁,表锁,行锁,悲观锁,乐观锁,间隙锁)

    读锁和写锁 介绍 MyISAM表锁中的读锁和写锁 读锁(共享锁S): 对同一个数据,多个读操作可以同时进行,互不干扰.加锁的会话只能对此表进行读操作,其他会话也只能进行读操作.MyISAM的读默认是加 ...

  3. 理解悲观锁乐观锁、同步锁、读锁、写锁

    ava 锁分类 Java 中的锁有很多,可以按照不同的功能.种类进行分类,下面是我对 Java 中一些常用锁的分类,包括一些基本的概述 从线程是否需要对资源加锁可以分为 悲观锁 和 乐观锁 从资源已被 ...

  4. 图文深入解析 JAVA 读写锁,为什么读锁套写锁会死锁,反过来却不会?

    一.回顾基本的读写锁 我们知道读写锁 #java.util.concurrent.locks.ReentrantReadWriteLock 是一个 "读写互斥,写写互斥,读读共享" ...

  5. mysql locking_Mysql next-key locking,读锁,写锁

    MySQL innodb的间隙锁定(next-key locking)是为了防止幻读(phantom read), 当MySQL的isolation level设为repeatable read的时候 ...

  6. MySQL:行锁、表锁、乐观锁、悲观锁、读锁、写锁

    1.锁的分类 1.1从对数据操作的类型来分 读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响. 结论1: --如果某一个会话 对A表加了read锁,则 该会话 可以对A表进行读操作 ...

  7. MySQL中的读锁和写锁

    转载自 MySQL中的读锁和写锁 在数据库的锁机制中介绍过,数据的锁主要用来保证数据的一致性的,数据库的锁从锁定的粒度上可以分为表级锁.行级锁和页级锁.在我的博客中重点介绍过MySQL数据库的行级锁. ...

  8. mysql乐观锁与事务_Mysql中的读锁,写锁,乐观锁及事务隔离级别和并发问题

    mysql读锁,写锁,乐观锁 读锁,也叫共享锁(shared lock) SELECT * FROM table_name  WHERE ...  LOCK IN SHARE MODE 写锁,也叫排他 ...

  9. 读锁(共享锁)写锁(独占锁)解析

    读锁(共享锁)写锁(独占锁)解析 在多线程环境下一个资源类被读是没有任何问题的,所以满足并发要求,但是,如果有一个线程去写共享资源,那么就不应该再有其他线程可以对该资源进行读或写了.也就是说,读-读可 ...

最新文章

  1. 茅台App首发就登顶!单日下载量43万,甚至还没开始试运行
  2. 通用数据库管理工具DBeaver
  3. 工具用的好下班走的早
  4. 全球及中国医用敷料市场销售前景与竞争格局研究报告2022版
  5. java类与对象实验_JAVA类与对象实验报告
  6. 一个程序如何连接到外网_如何开发制作小程序?做一个电商带直播小程序
  7. threejs 加载两个场景_threejs中的三维场景操作
  8. python发送包含html、图片、附件和链接的邮件
  9. 我如何将Google I / O 2018的兴奋带给尼日利亚沃里的115个人
  10. python 函数式编程包_python 函数支持函数式编程的包operator partial
  11. Oracle→简介、用户、数据字典、表空间及其文件
  12. paroot忘记root密码
  13. 405.十六进制数 (力扣leetcode) 博主可答疑该问题
  14. mysql数据库表中重命名语句_mysql数据库重命名sql语句
  15. ArcGIS小图斑根据相邻地类属性融合。
  16. 处理安全检查的项目代码异常解决记录
  17. 电脑英语Computer English
  18. 如何在虚拟一个USB设备
  19. 深入剖析JDK动态代理源码实现
  20. Android View部分消失效果实现

热门文章

  1. 电脑桌面计算机打开无响应,电脑任务栏假死点击没反应的解决方法(win7与xp)
  2. framemaker中遍历及判断其属性是否存在
  3. $wnd and $doc Calling native JavaScript with JSNI
  4. 【RL系列】马尔可夫决策过程——Gambler's Problem
  5. 基于激光雷达的室内探测系统
  6. C语言(经典编程题:报数游戏)
  7. Mac下用docker安装阿波罗Apollo
  8. 2022最新SCI影响因子TOP100榜单
  9. 会php学java入门要多久_php自学需要多久
  10. [日常]mov文件转换为gif