Linux Programming 学习笔记 :File Locking

Advisory lock vs Mandatory lock

建议锁和强制锁。

  • Advisory lock
    • 建议性锁并不从内核限制程序访问文件,而是依赖各个合作进程(cooperating process)之间遵循相应的规则。
    • 这意味着进程可以自由地忽略 fcntl()(或flock())的使用,而只需对文件执行 I/O。
  • Mandatory lock
    • 强制内核检查每次open, read, 和 write操作,保证调用进程没有违反对正在访问的文件的锁。

Advisory mode locking is sometimes referred to as discretionary locking, while mandatory locking is sometimes referred to as enforcement-mode locking. SUSv3 doesn’t specify mandatory locking, but it is available (with some variation in the details) on most modern UNIX implementations.

本文介绍flock()fcntl()

flock(), which places locks on entire files; and
fcntl(), which places locks on regions of a file.

flockfcntl在内核中都用struct file_lock实现。其主要差别就在于owner的不同。
如果lock的owner相同,conflict的检测就会跳过,即相同owner的lock可以递归申请。
flock锁的粒度为整个文件。fcntl提供了字节范围粒度的lock,即 byte-range locking

Flock

flock(2) - Linux man page
在这里插入图片描述

  • Values for operation:
    operation表明锁的类型,需要指明LOCK_SH, LOCK_EX, 和 LOCK_UN中的其中一个。
    并且如果|LOCK_NB,那么 flock() 不会被阻塞,而是返回error:EWOULDBLOCK
ValueDescription
LOCK_SH对 fd 引用的文件加共享锁 shared lock
LOCK_EX对 fd 引用的文件加排他锁 exclusive lock
LOCK_UN对 fd 引用的文件解锁
LOCK_NB非阻塞的锁请求
  • Capability of flock() locking types :
    Capability of *flock()* locking types

多个进程可以同时对一个文件持有shared lock,只有一个进程可以对一个文件持有exclusive lock(其他进程不能再持有shared lock或是exclusive lock)。
注意,无论文件的访问模式(read, write, or read-write)如何,进程都可以放置共享或排他锁。
通过再次调用flock() ,可以将现有的共享锁转换为排他锁(反之亦然)。如果另一个进程持有文件上的共享锁,则将共享锁转换为排他锁将阻塞,除非还指定了 LOCK_NB。

Semantics

flock对整个文件上锁。flock的owner是内核态open fd,而不是用户态fd或者inode。
在这里插入图片描述

A file lock obtained via flock() is associated with the open file
description , rather than the file descriptor or the file (i-node)
itself.

  • 若调用dup(),dup2(), or fcntl() F_DUPFD 复制fd,新的fd指向同一个内核态中的open fd,故指向同一个的file lock。 (以下以go语言做示例)
fd, _ := syscall.Open("lockfile", syscall.O_RDWR, 0644)
newfd, _ := syscall.Dup(fd)
if err = unix.Flock(fd, unix.LOCK_EX|unix.LOCK_NB); err != nil {
  log.Fatal(err)
}
if err = unix.Flock(newfd, unix.LOCK_EX|unix.LOCK_NB); err != nil {
  log.Fatal(err)
}

fd和newfd指向同一个open fd,对fd上锁,并不影响通过newfd上锁。

  • 若调用open()获取相同文件的新fd,fd1,fd2对应内核态中不同的open fd。
fd1, _ := syscall.Open("lockfile", syscall.O_RDWR, 0644)
fd2, _ := syscall.Open("lockfile", syscall.O_RDWR, 0644)
if err = unix.Flock(fd1, unix.LOCK_EX|unix.LOCK_NB); err != nil {
  log.Fatal(err)
}
if err = unix.Flock(fd2, unix.LOCK_UN|unix.LOCK_NB); err != nil {
  log.Fatal(err)              /*return: resource temporarily unavailable, Locked out by lock on 'fd1'*/
}

对fd2上锁被阻塞。

Limitation
  • 锁的粒度为整个文件。
  • 只能为advisory locks
  • Many NFS implementations don’t recognize locks granted by flock().

Fcntl

fcntl(2) - Linux man page
在这里插入图片描述

flock structure
struct flock {
    short l_type; /* Lock type: F_RDLCK, F_WRLCK, F_UNLCK */
    short l_whence; /* How to interpret 'l_start': SEEK_SET, SEEK_CUR, SEEK_END */
	off_t l_start;/* Offset where the lock begins */
	off_t l_len;/* Number of bytes to lock; 0 means "until EOF" */
	pid_t l_pid; /* Process preventing our lock (F_GETLK only) */ 
}; 
锁的类型

l_type表明想要加的锁的类型, 可以为下表的其中之一。F_RDLCK,F_WRLCK分别对应 flock() 中的LOCK_SHLOCK_EXF_UNLCK可以类比LOCK_UN

Lock typeDescription
F_RDLCK加写锁
F_WRLCK加读锁
F_UNLCK移除已有的锁

注意,如果要加读锁,那么文件必须以读权限打开。同样,加写锁,需要以写权限打开。如果加锁但权限不够,返回EBADF

锁的范围

l_whence, l_start, 和 l_len规定了锁作用的字节范围,锁的开始位置由l_startl_whence共同决定。

  • l_start: 开始位置的偏移量
  • l_whence:开始的位置。
    l_whenceSEEK_CURSEEK_END时,l_start可以为负数。
l_whence可选参数Description
SEEK_SETthe start of the file
SEEK_CURthe current file offset
SEEK_ENDthe end of the file
  • l_len : 锁定文件的长度
    l_len设为0有特殊的含义:

    锁定从 l_start 和 l_whence 指定的点到文件末尾的所有字节,无论文件增长多大。

    若锁定整个文件,通常将l_whence设为SEEK_SET, l_start设为0,l_len设为0.

cmd
  • F_SETLK: 给当前文件上锁 (l_type 为 F_RDLCK 或 F_WRLCK) 或 释放锁 (l_type为 F_UNLCK)
  • F_SETLKW :阻塞状态的 F_SETLK,当前文件正在被锁住,该函数一直阻塞。
  • F_GETLK: 获取当前锁的状态(l_type 必须为 F_RDLCK 或 F_WRLCK)

将不同模式的锁放在我们已经持有的锁中间会产生三个锁:在新锁的两侧创建两个先前模式中的较小锁。
Splitting of an existing read lock by a write lock by the same process:
在这里插入图片描述

record lock与进程和inode关联。当一个进程终止时,它的所有record lock都被释放。每当一个进程关闭一个文件描述符时,该进程在相应文件上持有的所有锁都会被释放,而不管获得锁的文件描述符是什么。

Reference

  1. The Linux Programming Interface Chapter 55.
  2. Advanced Programming in the UNIX Environment 14.3
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值