您的位置:首页 > 运维架构 > Linux

Linux文件锁

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

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

文件锁的代码实现主要依赖于函数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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息