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个字节)。
有一点值得注意的是,文件锁的正确使用方式应该是读锁和read()函数一起使用,而写锁必须和write()一起使用,例如上面的代码中只要写过程没有完成,是不能去读的,但是我们在另一个进程去用read去读a.txt是可以读到的。
而读写锁的正确使用方式是在读之前加一把读锁,而在写之前加一把写锁。文件锁并不能锁定读写的函数read()/write(),只能阻止其他进程的加锁行为,导致其他进程加不上锁,因此:文件锁的正确用法,在调用read函数之前应该加上一把读锁,在调用之前加一个写锁,读写完毕之后马上释放锁;
上面的代码加了读锁,下面是写的代码。
可以测试,在读的过程没有结束之前,就是读锁没有释放之前,去进行写操作的话,写锁是无法成功锁上的,而只有当读锁被释放了之后,才能成功加上写锁。
上面所有代码都必须包含myfile.h头文件,这个头文件的内容是:
#ifndef _MYFILE_H
#define _MYFILE_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#endif
文件锁允许多个进程同时读文件(因为读操作并没有影响文件的内容),但不允许同时写,一些读一些写也不行,所以文件锁分为读锁和写锁。读锁的效果是允许其他进程读文件,但不允许其他进程写文件,而写锁的效果是即不允许其他进程读文件,也不允许其他进程写文件。
文件锁的代码实现主要依赖于函数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 socket 初步
- Linux Kernel 4.0 RC5 发布!
- linux lsof详解
- linux 文件权限
- Linux 执行数学运算
- 10 篇对初学者和专家都有用的 Linux 命令教程
- Linux 与 Windows 对UNICODE 的处理方式
- Ubuntu12.04下QQ完美走起啊!走起啊!有木有啊!
- 解決Linux下Android开发真机调试设备不被识别问题
- 运维入门
- 运维提升
- Linux 自检和 SystemTap
- Ubuntu Linux使用体验
- c语言实现hashmap(转载)
- Linux 信号signal处理机制
- linux下mysql添加用户
- Scientific Linux 5.5 图形安装教程
- Linux 下无损图片压缩小工具介绍