一.文件锁的概念
在Linux操作系统中通常有许多并发型的场景,比如多个用户想要操作同一个一个文件,这样就会导致不知道谁在读或者写文件.那么这个时候文件锁的作用就体现出来了.
文件锁一般分为共享型锁(读锁)和排他型锁(写锁),那么两种锁的特点,简而言之就是 共享型锁可以共存,排他型锁不能共存.再简而言之,一个文件 A 用户上了读锁,B用户也可以上读锁,但是如果有C上了一个写锁,那么不好意思 排他型 和共享型锁不能共存, 那么则 后上锁的C将会被阻塞,直到文件上的共享型锁都被释放,那么C才能拿到锁.
二.难点讲解
现在用一段示例代码解释这个过程:
上锁这个操作通过fcntl( int fd, "锁的操作", " 锁的结构体 ");这个函数对文件进行上锁,锁定文件通过fd,什么是fd.书接上文socket编程,在linux中这类fd都相当于是文件句柄,linux内一切皆文件,只不过把文件抽象成了一个int类型的数字,我们不用管这个数字的含义,你只管去操作这个数字,linux内核会去帮你操作,相当于linux内核给你提供了一个接口,也就是这个数字接口,一个API,这个数字就相当于文件.... 有点啰嗦 下面继续
有几个部分可能初学者难以理解 一个就是" 锁的结构体 ",另一个就是"锁的操作"
锁的结构体:
通过man fcntl 可以看到帮助文档
type : 锁的具体类型 读 写 解锁 这个很好理解
whence : 从哪开始 比如文件的开头 当前 末尾 取决于文件的当前指针 有没有设置文件的偏移值
start: 从whence指定 的地方 你想偏移多少 往哪偏移 正数代表往后 -代表往前
len:表示你想锁定多少个字节的文字 0表示全文
pid: 这里主要是记录 是哪个进程给这个文件上锁,一般是默认-1
struct flock {
...
short l_type; /* Type of lock: F_RDLCK,
F_WRLCK, F_UNLCK */
short l_whence; /* How to interpret l_start:
SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start; /* Starting offset for lock */
off_t l_len; /* Number of bytes to lock */
pid_t l_pid; /* PID of process blocking our lock
(set by F_GETLK and F_OFD_GETLK) */
...
};
锁的操作:
锁的操作我概括两种:
1.拿锁 F_GETLK
拿锁的意思是你可以判断文件中是否有锁,如果有的话可以取出锁的信息并放入锁的结构体中,
上文我讲的type 锁的类型 还有 pid 对文件上锁的进程id,从这体现出其意义.
2.设置锁 F_SETLKW(阻塞) | FSETLK(非阻塞)
设置锁就算是上锁的操作,本质意义上你要上锁的话就要设置好一个锁的结构体,然后进行上锁操作,把结构体和这个文件绑定..
这里有点区别的是 有无这个 W ,有的话则是阻塞型上锁,有这个W 你去上锁失败,比如文件已经上锁了,他则会阻塞,直到文件无锁,它则直接对其进行上锁, 另一个无阻塞的上锁操作 则是如果文件有锁,则直接返回错误!
三.具体代码
简述一下整个过程, 创建一个文件并且对其上读锁 并打印出相关的上锁信息 比如谁上的锁 上的什么锁
如果看不懂在干嘛 请反复会看 二 讲的难点讲解
这里我专门写了给函数方便我进行锁的操作 不够实现上锁 解锁还是依靠fcntl这个函数
你们拿到代码可以开两个客户端实验,同时打开这个文件,因为都是读锁,所以没问题,可以一个文件共存两个共享型锁,但是如果已经上了一个共享型锁,再上一个排他型锁,那么后上锁的那个就会被阻塞,直到第一个用户释放锁.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#define FILE_NAME "lock_file.txt"
int flock_set(int fd,int type)
{
printf("pid=%d coming!",getpid());
struct flock fflock;
memset(&fflock,0,sizeof(struct flock));
fcntl(fd,F_GETLK,&fflock);
if(fflock.l_type!=F_UNLCK){
if(fflock.l_type==F_RDLCK){
printf("This file have a ReadLock by pid:%d!\n",fflock.l_pid);
}else if(fflock.l_type==F_WRLCK){
printf("This file have a WriteLock by pid:%d!\n",fflock.l_pid);
}
}
fflock.l_type=type;
fflock.l_whence=SEEK_SET;
fflock.l_start=0;
fflock.l_len=0;
fflock.l_pid=-1;
if(fcntl(fd,F_SETLKW,&fflock)<0){
printf("SETLock ERROR:%s\n",strerror(errno));
}
switch(fflock.l_type){
case F_RDLCK:
printf("The Readlock has been Set by pid:%d!\n",getpid());
break;
case F_WRLCK:
printf("The Writelock has been Set by pid:%d\n",getpid());
break;
case F_UNLCK:
printf("The Unlock has been Set by pid:%d\n",getpid());
break;
default:
break;
}
printf("pid:%d out!\n",getpid());
return 0;
}
int main (void){
int fd=0;
fd=open(FILE_NAME,O_RDWR|O_CREAT,0666);
if(fd<0){
printf("open error: %s\n",strerror(errno));
exit(-1);
}
flock_set(fd,F_RDLCK);
getchar();
flock_set(fd,F_UNLCK);
getchar();
close(fd);
return 0;
}
具体改哪里可以看到效果呢?flock_set(fd,F_WRLCK); 这里改成写锁就可以了 cp 两份代码,一个客户端运行读锁,另一个运行写锁 可以看到马上被阻塞了.
创作不易- -评论点赞 一健三连 支持博主谢谢啦~