linux 文件记录锁

1. 什么是文件记录锁?

   是对文件某个范围的锁定

2.文件记录锁的功能?

 当一个进程正在读或者修改文件的某个部分的时候,它可以阻止其他进程修改同一文件区

3. 文件记录锁的函数接口?

      fcntl()  此系统调用可以用来对已打开的文件描述符进行各种控制操作以改变已打开文件的各种属性,根据传入不同的操作类型命令cmdfcntl会执行不同的操作,fcnt根据cmd不同,接收可变的参数。具体有以下五种类型的操作:

/* Do the file control operation described by CMD on FD. 
   The remaining arguments are interpreted depending on CMD. */  
int fcntl (int __fd, int __cmd, ...);  
  
//根据cmd的不同有以下三种类型的调用  
int fcntl(int fd, int cmd);  
int fcntl(int fd, int cmd, long arg);  
int fcntl(int fd, int cmd, struct flock *lock);

/* 
cmd = F_DUPFD,复制一个文件描述符; 
*/  
int fcntl(int fd, int cmd);  
  
/* 
cmd = F_GETFD,获得文件描述符标志; 
cmd = F_SETFD,设置文件描述符标志;arg = 描述符标志的值,目前只定义了一个标志: FD_CLOEXEC 
int fcntl(int fd, int cmd); 
int fcntl(int fd, int cmd, long arg); 
*/  
  
/* 
cmd = F_GETFL,获得文件状态标志; 
cmd = F_SETFL,设置文件状态标志;arg = 状态标志的值 
int fcntl(int fd, int cmd); 
int fcntl(int fd, int cmd, long arg); 
*/  
  
/* 
cmd = F_GETOWN,获得当前接收SIGIO和SIGURG信号的进程ID或进程组ID 
cmd = F_SETOWN,设置接收SIGIO和SIGURG信号的进程ID或进程组ID;arg = 进程ID或进程组ID 
int fcntl(int fd, int cmd); 
int fcntl(int fd, int cmd, long arg); 
*/  
  
/* 
Return value: 
 
对于成功的调用,根据操作类型cmd不同,有以下几种情况: 
       F_DUPFD  返回新的文件描述符 
       F_GETFD  返回文件描述符标志 
       F_GETFL  返回文件状态标志 
       F_GETOWN 进程ID或进程组ID 
       All other commands  返回0 
调用失败, 返回-1,并设置errno。 
*/  
上面四个功能都是fcntl提供的很常用的操作,关于记录锁的功能就是fcntl提供的第五个功能,具体使用如下:
int fcntl(int fd, int cmd, struct flock *lock);  
  
/* 
cmd = F_GETLK,测试能否建立一把锁 
cmd = F_SETLK,设置锁 
cmd = F_SETLKW, 阻塞设置一把锁 

F_GETLK-判断由flockptr描述的锁是否会被另外一把锁排斥,若存在,则把现存锁的信息写入到flockptr中,若不存在,则除了将l_type设置为F_UNLCK之外,结构中其余信息不变;

F_SETLK-设置由flockptr描述的锁,如果按照共享读锁和独占写锁规则,不允许加锁,则立即返回错误码;
 -此命令也用于清除flockptr说明的锁,l_type=F_UNLCK


F_SETLKW-是F_SETLK的阻塞版本,当不满足加锁规则时候,进程进入休眠,如果请求创建的锁已经可用,则休眠由信号中断,进程被唤醒;
*/  
需要注意的是,用F_GETLK测试能否建立一把锁,然后接着用F_SETLK或F_SETLKW企图建立一把锁,
由于这两者不是一个原子操作,所以不能保证两次fcntl之间不会有另外一个进程插入并建立一把相关的锁,
从而使一开始的测试情况无效。所以一般不希望上锁时阻塞,会直接通过调用F_SETLK,并对返回结果进行
测试,以判断是否成功建立所要求的锁

//POSIX只定义fock结构中必须有以下的数据成员,具体实现可以增加  
struct flock {  
      short l_type;    /* 锁的类型: F_RDLCK, F_WRLCK, F_UNLCK */  
      short l_whence;  /* 加锁的起始位置:SEEK_SET, SEEK_CUR, SEEK_END */  
      off_t l_start;   /* 加锁的起始偏移,相对于l_whence */  
      off_t l_len;     /* 上锁的字节数,如果为0,表示从偏移处一直到文件的末尾*/  
      pid_t l_pid;     /* 已经占用锁的PID(只对F_GETLK 命令有效) */  
      /*...*/  
};  

4.  共享读锁与独占写锁:

      多个进程在给定的字节上可以有一把共享的读锁,但是在一个给定字节上只能有一个进程独占一把写锁;
如果在一个给定字节上已经有了一把或者多把读锁,可以继续添加读锁,但是不能在该字节上加写锁;如果在一个字节上已经有了一把独占写锁,则不能再添加任何读/写锁;
注意:这个规则只适用于不同进程提出的锁请求,如果单个进程对一个文件区间已经有了一把锁,后来又企图对同一文件区加另一把锁,那么新锁将替换旧锁;

5. 记录锁的隐含继承和释放:
(1) 进程终止时,所建立的锁全部被释放;
(2) 关闭任何一个描述符,则该进程通过该描述符可以引用的文件上的任何一把锁都被释放;
(3) fork产生的子进程不继承父进程锁设置的锁;
(4) 在执行了exec后,新程序可以继续执行原来程序的锁;如果对一个描述符设置了close-on-exec,则exec执行时候,文件描述符被关闭,对应锁也被释放;

6. 在文件尾加锁:
(1) 在加锁之前最好是对文件当前位置或者当前长度指定一把锁,因为在lseek和加锁调用之间,可能有另外一个进程在改变该文件的长度;
(2) 下面代码第一次加锁的时候,得到一把锁,从文件尾端开始,包括以后添加的任何数据,都会加锁;解锁的时候,文件尾端已经变化了,所以并没有解锁;

7. 强制性锁和建议性锁:
合作进程,多个进程都用一致的方式处理记录锁,完成某些任务,这些进程集合就是合作进程;
建议性锁:建议性锁不做强制检查锁规则,需要进程自己获取,检查是否有锁存在,对于合作进程来说,建议性锁是可行的,但是对于某些非合作进程,他们不进程检查,就对文件进行改写,就会对当前文件造成影响;如建议性锁可以比如成红绿灯,只是建议性的,因为还是有人可以闯红灯;
强制性锁:内核对每个open,read,write系统调用都进行检查,检查访问的文件是否违背了锁规则,如果违背了锁规则,则该IO调用被禁止;

参考博客:

https://blog.csdn.net/anonymalias/article/details/9197641

https://www.cnblogs.com/wanpengcoder/p/5305749.html


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值