Linux 文件锁
当多个进程同时访问操作同一个文件时,我们怎么保证文件数据的正确性。
linux通常采用的方法是文件上锁,来避免共享资源的产生竞争状态。
文件锁包括建议性锁和强制性的锁:
建议性的锁 :顾名思义,相对温柔一些,在对文件进行锁操作时,会检测是否已经有锁存在,并且尊重已有的锁。在一般的情况下,内核和系统都不使用建议锁。
强制性锁 :由内核执行的锁,当一个文件被上锁进行写入操作的时候, 内核将阻止其他进程进行读写操作。采用强制性的锁对系统的性能影响很大,每次进行读写操作都必须 检查是否有所存在。
在linux中对文件进行锁操作,可以使用lockf()和fcntl()这两个函数:
前者对文件施加建议性锁,后者为两种锁都行。另外fcntl还可以对文件的某一记录上锁。
fcntl函数原型:
int fcntl( int fd, int cmd, struct flock *lock );
fd为文件描述符
cmd为一些命令参数
flcok结构体用来设置记录锁的具体状态。
fcntl() 对已打开的文件描述符进行操作,并根据命令参数的不同能够执行不同的任务。
关于文件锁的几个命令选项如下:
F_GETLK 根据lock参数值,决定是否上文件锁
F_SETLK 设置lock参数值的文件锁
F_SETLKW 这是 F_GETLK的阻塞版本,在无法获取锁时,会进入睡眠状态- flock结构体的定义如下:
struct flock {
short l_type;
off_t l_start;
short l_whence;
off_t l_len;
pid_t l_pid;
}
l_type有三个选项:
F_RDLCK : 共享锁,只读用
F_WRLCK : 独占锁(写操作锁)
F_UNLCK : 解除锁定
l_start 为相对位移量l_whence 必须是以下几个值之一( 在 unistd.h 中定义):
SEEK_SET : 文件开始位置
SEEK_CUR: 文件当前位置
SEEK_END: 文件末尾位置
l_len 加锁的长度
l_pid当前文件操作的进程id号
{
int i = 20; //20秒时间
//打开文件
if ((fp = fopen("./test.ok", "r+b")) == NULL)
printf("file open error!\n");
//给该文件加锁
if (flock(fp->_fileno, LOCK_EX) != 0)
printf("file lock by others\n");
//进入循环,加锁时间为20秒,打印倒计时
while(1)
{
printf("%d\n", i--);
sleep(1);
if (i == 0)
break;
}
//20秒后退出,关闭文件
fclose(fp);
//文件解锁
flock(fp->_fileno, LOCK_UN);
return 0;
}
文件2 test02.c,代码如下:
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp = NULL;
int i = 0;
//打开文件
if ((fp = fopen("./test.ok", "r+b")) == NULL)
printf("file open error!\n");
flock(fp->_fileno, LOCK_EX); //文件加锁
while(1) //进入循环
{
printf("%d\n", i++);
sleep(1);
}
fclose(fp); //关闭文件
flock(fp->_fileno, LOCK_UN); //释放文件锁
return 0;
}
首先运行test01.c,紧接着运行test02.c(运行test01.c后20秒内要运行test02.c否则看不到现象)
现象:
test01.c执行起来以后,开始倒计时。
此时运行test02.c会阻塞在加锁处。
当test01.c运行20秒后关闭文件,并释放文件锁后,test02.c会开始运行。
测试:
1.************************************
2.************************************************
测试竟然不成功。