天天看点

文件锁-flock和fcntl

文件级的锁:对整个文件加锁,flock系统调用

文件内范围的锁:对文件的某个范围加锁,fcntl库函数

1. flock

flock是系统调用,加的建议锁

https://man7.org/linux/man-pages/man2/flock.2.html

tips:

flock的锁的语义:获取到的锁是与打开的文件描述符,而不是文件描述符或者inode相关联

(1)对于open同一个文件多次,获取到的不同fd,flock会认为是不同的,所以再加flock会block

(2)flock创建的锁是和fd相关的,所以复制dup(fd)和fork产生的fd,都是同一把锁

demo:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/file.h>
int main (int argc, char ** argv)
{
    int ret;
    int fd1 = open("tmp.txt",O_RDWR);
    int fd2 = open("tmp.txt",O_RDWR);
    //int fd2 = dup(fd1);
    printf("fd1: %d, fd2: %d\n", fd1, fd2);
    ret = flock(fd1,LOCK_EX);
    printf("get lock1, ret: %d\n", ret);
    ret = flock(fd2,LOCK_EX|LOCK_NB);
    printf("get lock2, ret: %d\n", ret);
    return 0;
}
           

2. fcntl

是GNU C库函数,既可以加建议锁和强制性锁

https://man7.org/linux/man-pages/man2/fcntl.2.html

#include <fcntl.h>
struct flock {
	short l_type; // F_RDLCK,F_WRLCK,F_UNLCK
	short l_whence;	// SEEK_SET,SEEK_CUR,SEEK_END,起始位置,文件的当前偏移量,结尾位置
	off_t l_start; // offset where the lock begins
	off_t l_len; // number of bytes to lock
	pid_t l_pid; // process preventing our lock(only F_GETLK only)
};
struct flock flockinfo;
fcntl(fd, F_SETLK, &flockinfo)
           

F_GETLK:检测是否可以获取指定区域的锁,实际并不获取这把锁,如果可以返回的l_type是F_UNLCK

F_SETLK:更新锁,如果有冲突返回EAGAIN

F_SETLKW:更新锁,如果有冲突,则阻塞直到锁的请求被满足

demo:

#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>

int main() {
    struct flock lock;
    lock.l_whence = SEEK_SET;
    lock.l_type = F_WRLCK;
    lock.l_start = 0;
    lock.l_len = 100;
    lock.l_pid = getpid();

    const char* fname = "test.txt";
    int fd = open(fname, O_RDWR);
    if (fd < 0) {
        printf("open err: fname %s\n", fname);
        return -1;
    }
    int ret = fcntl(fd, F_SETLK, &lock);
    if (ret == 0) {
        printf("ltyp %d range(%d:%d)\n", lock.l_type, lock.l_start, lock.l_len);
    } else {
        printf("error: ltyp %d range(%d:%d)\n", lock.l_type, lock.l_start, lock.l_len);
    }
    close(fd);
    return 0;
}
           

3. flock和fcntl的区别和联系

结论1:

两者判断锁是否冲突的区别:

flock的owner是内核态的open fd,判断是否冲突也是根据owner,如果owner相同则可以递归申请。

这样解释:多次open同一个文件内核有两个fd,所以owner不同,再加flock会锁住,dup则在内核态还是一个owner,不会冲突

Fcntl的owner是进程,不是fd也不是inode

结论2:

两者的联系:

flock创建的锁和fcntl创建的锁之间的交互是未定义的行为,因此应用程序应该只使用其中一种文件加锁方法。——《linux-unix系统编程手册》

reference:

[1] https://www.jianshu.com/p/8b355893f709

[2] https://yxkemiya.github.io/2019/08/19/file-lock/

[3] 《linux-unix系统编程手册》55.2和55.3章节

[4] 《unix环境高级编程》14.3章节