Linux文件锁

Posted uestclr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux文件锁相关的知识,希望对你有一定的参考价值。

当多个进程同时操作一个文件时,必然会引发数据之间的冲突,例如一个进程在读文件,另一个进程却在写文件,或者是两个进程都在同时写文件。为了使得多个进程操作文件时的安全性,可以使用文件锁。


文件锁允许多个进程同时读文件(因为读操作并没有影响文件的内容),但不允许同时写,一些读一些写也不行,所以文件锁分为读锁和写锁。读锁的效果是允许其他进程读文件,但不允许其他进程写文件,而写锁的效果是即不允许其他进程读文件,也不允许其他进程写文件。


文件锁的代码实现主要依赖于函数fcntl()和一个结构体struct flock来实现。


fcntl(int fd,F_SETLK/F_SETLKW,struct flock*),第一个参数时操作文件的文件描述符,第二个参数时一个宏,代表锁定的方式,F_SETLK表示锁定失败就返回-1,而F_SETLKW表示锁不上就一直等待,等到其他进程释放锁时候才加锁。一般有两种选择,第三个参数是一个锁结构指针。


struct flock

   short l_type;//锁的类型,包括读锁,写锁和释放锁

   short l_whence;//锁定起始点的参考位置

   off_t l_start;//锁定起始点的偏移量

   off_t l_len;//锁定区域的大小,锁定的长度

   pid_t l_pid;//锁定进程的PID,只有GETLK用的到,给-1即可

;

l_type锁的类型:F_RDLCK/F_WRLCK/F_UNLCK(包括读锁,写锁,和释放锁)

l_whence:SEEK_SET/SEEK_END/SEEK_CUR(分别表示从头开始,从末尾开始和从当前位置开始偏移)

注意:文件锁不是锁定整个文件,而是锁定文件的一部分。锁定部分由l_whence/l_start/l_len三个联合决定;

 

比如:l_whence选择SEEK_SET,l_start = 10,l_len = 20;锁定的区域就是:第11个到第30个(文件头偏移10,锁定20个字节)。

void main()
   int fd = open("a.txt",O_RDWR);
   if (fd == -1) perror("open"),exit(-1);
   struct flock lock;
   lock.l_type = F_RDLCK;//写锁
   lock.l_whence = SEEK_SET;
   lock.l_start = 10;
   lock.l_len = 20;
   lock.l_pid = -1;
   int res = fcntl(fd,F_SETLK,&lock);
   if (res == -1) printf("上锁失败!\\n");
   else printf("锁定成功\\n");
   sleep(15);
   close(fd);


有一点值得注意的是,文件锁的正确使用方式应该是读锁和read()函数一起使用,而写锁必须和write()一起使用,例如上面的代码中只要写过程没有完成,是不能去读的,但是我们在另一个进程去用read去读a.txt是可以读到的。


而读写锁的正确使用方式是在读之前加一把读锁,而在写之前加一把写锁。文件锁并不能锁定读写的函数read()/write(),只能阻止其他进程的加锁行为,导致其他进程加不上锁,因此:文件锁的正确用法,在调用read函数之前应该加上一把读锁,在调用之前加一个写锁,读写完毕之后马上释放锁;

void main()
   int fd = open("a.txt",O_RDWR);
   if (fd == -1) perror("open"),exit(-1);
   struct flock lock;
   lock.l_type = F_RDLCK;
   lock.l_whence = SEEK_SET;
   lock.l_start = 10;
   lock.l_len = 5;
   lock.l_pid = -1;
   int res = fcntl(fd,F_SETLK,&lock);
   if (res == -1) printf("上锁失败!\\n");
   else printf("锁定成功,开始读文件\\n");
   char buf[5] = ;
   read(fd,buf,sizeof(buf));
   sleep(25);
   printf("读完了,释放锁\\n");
   lock.l_type = F_UNLCK;
   fcntl(fd,F_SETLK,&lock);
   sleep(10);
   close(fd);
   printf("%s\\n",buf);

上面的代码加了读锁,下面是写的代码。

#include "myfile.h"

void main()
   int fd = open("a.txt",O_RDWR);
   if (fd == -1) perror("open"),exit(-1);
   struct flock lock;
   lock.l_type = F_WRLCK;
   lock.l_whence = SEEK_SET;
   lock.l_start = 10;
   lock.l_len = 20;
   lock.l_pid = -1;
   int res = fcntl(fd,F_SETLK,&lock);
   if (res == -1)
      printf("上锁失败!\\n");
   
   else //只有上锁成功才能进行读写操作
      printf("锁定成功\\n");
      write(fd,"ooooo",5);
   
   close(fd);

可以测试,在读的过程没有结束之前,就是读锁没有释放之前,去进行写操作的话,写锁是无法成功锁上的,而只有当读锁被释放了之后,才能成功加上写锁。


上面所有代码都必须包含myfile.h头文件,这个头文件的内容是:

#ifndef _MYFILE_H
#define _MYFILE_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#endif



以上是关于Linux文件锁的主要内容,如果未能解决你的问题,请参考以下文章

feof() 在 C 中的工作原理

如何让linux加载当前目录的动态库

lseek 与 ioctl

建议性锁和强制性锁

linux常用的命令行快捷键

linux运维快捷键