Linux系统之 文件锁 fcntl函数使用

在多数unix系统中,当多个进程/线程同时编辑一个文件时,该文件的最后状态取决于最后一个写该文件的进程。

文件锁(也叫记录锁)的作用是,当一个进程读写文件的某部分时,其他进程就无法修改同一文件区域。
借助fcntl函数来实现锁机制。允许对文件中任意字节区域加锁,短至一个字节,长至整个文件。
操作文件的进程没有获得锁时,可以打开,但无法执行read、write操作。
适合环境——当前系统中该进程只能起一个。
实现原理——当一个进程打开了这个文件,另一个进程发现文件被打开了,就无法再打开这个文件了。
对于有些应用程序,如数据库,各个进程需要保证它正在单独地写一个文件。这时就要用到文件锁。

文件锁——读共享,写独占。

fcntl函数

#include <unistd.h>
int fcntl(int fd, int cmd, ... /* arg */ );1:	文件描述符
参2F_SETLK(struct flock *)		设置文件锁(trylock)
		F_SETLKW(struct flock *)	设置文件锁(lock) W-->wait 阻塞版本
		F_GETTLK(struct flock *)	获取文件锁
参3struct 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=SEEK_SET;l_start=0;开始于文件头
               off_t l_len;    	区域字节长度若l_len=0, 表示锁的范围可以扩大到最大可能偏移量
               pid_t l_pid;     持有该所的进程ID,持有的锁能阻塞当前进程,仅由F_GETLK返回
               ...
           };

锁可以在文件尾处开始或者越过尾端开始,但是不能在文件起始位置之前开始
若l_len=0, 表示锁的范围可以扩大到最大可能偏移量,这意味着不管向文件中追加多少数据,
它们都可以处于锁的范围内,而且起始位置可以任意。
设置l_start和l_whence指向文件的起始位置,
并且指定l_len=0,以实现对整个文件加锁(一般l_start=0, l_whence=SEEK_SET)。

使用锁的基本规则:
  • 任意多个进程在一个给定的字节上可以有一把共享的读锁(F_RDLCK),但是在一个给定的字节上只能有一个进程有一把独占性写锁(F_WRLCK)
  • 如果在一个给定字节上已经有一把或多把读锁,则不能在该字节上再加写锁。
  • 如果在一个字节上已经有一把独占性写锁,则不能再对它加 任何读锁
  • 对于单个进程而言,如果进程对某个文件区域已经有了一把锁,然后又试图在相同区域再加一把锁,则新锁会替换旧锁
  • 加读锁时,该描述符必须是读打开,加写锁时,该描述符必须是写打开

demo

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#define _FILE_NAME_ "./temp.lock"
int main() 
{
    int fd = open(_FILE_NAME_,O_RDWR|O_CREAT,0666);
    if(fd < 0){
        perror("open err");
        return -1;
    }
    struct flock flk;
    flk.l_type = F_WRLCK; //锁类型:独占性写锁F_WRLCK
    flk.l_whence = SEEK_SET ; //偏移基准位置:开头
    flk.l_start = 0; //起始偏移:0
    flk.l_len  =0;  //长度:0表示整个文件加锁
 
    if(fcntl(fd,F_SETLK,&flk) < 0){
        perror("get lock err");
        exit(1);
    }
    printf("%s locked!\n",_FILE_NAME_);
    while(1);
    return 0;
}
$ gcc demo_fcntl2.c -o lockf
$ ./lockf 
./temp.lock locked!

另一进程:

$ ./lockf 
get lock err: Resource temporarily unavailable
$ ./lockf 
get lock err: Resource temporarily unavailable
$ 
锁的继承和释放有以下三条原则:
  • 锁与进程和文件两者相关联。即当一个进程终止时,它所建立的所有锁均释放,对于描述符而言,无论它何时关闭,进程通过它引用的文件上的任何一把锁也都会释放
  • 由fork产生的子进程不继承父进程所设置的锁
  • 执行exec后,新程序可以继承原程序的锁。注意,如果对一个文件描述符设置了执行时关闭标志,那么当作为exec的一部分关闭该文件描述符时,将释放相应文件的所有锁
避免死锁

如果两个进程互相等待对方持有并且不释放的资源时,这两个进程就会进入死锁状态。
如果一个进程已经控制了文件中的一个加锁区域,然后它又试图对另一个进程控制的区域加锁,那么它就会进入睡眠,并有可能发生死锁。
检测到死锁时,内核必须选择一个进程接收错误返回。

总结
在多进程或多线程环境中,当多个应用需要读写同一个文件时,需要考虑对文件加锁,以保证对文件修改的一致性。
在使用文件锁时,应明确应用模式,防止死锁。

————————————————
原文链接:https://blog.csdn.net/weixin_44718794/article/details/106824275
原文链接:https://blog.csdn.net/guotianqing/article/details/80044087

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程一时爽Cxx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值