1、在文件已经共享的情况下如何操作,也就是当多个用户共同使用、操作一个文件的情况,这时,Linux 通常采用的方法是给文件上锁,来避免共享的资源产生竞争的状态。
2、fcntl()是一个非常通用的函数,它可以对已打开的文件描述符进行各种操作,不仅包括管理文件锁,还包括获得和设置文件描述符和文件描述符标志、文件描述符的复制等很多功能
3、fcntl()函数格式
所需头文件:#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
函数原型:int fcnt1(int fd, int cmd, struct flock *lock)
函数传入值:fd:文件描述符
cmd:
F_DUPFD:复制文件描述符
F_GETFD:获得fd 的close-on-exec 标志,若标志未设置,则文件经过exec()函数之后仍保持打开状态
F_SETFD:设置close-on-exec 标志,该标志由参数arg 的FD_CLOEXEC 位决定
F_GETFL:得到open 设置的标志
F_SETFL:改变open 设置的标志
F_GETLK:根据lock 参数值,决定是否上文件锁
F_SETLK:设置lock 参数值的文件锁
F_SETLKW:这是F_SETLK 的阻塞版本(命令名中的W 表示等待(wait))。在无法获取锁时,会进入睡眠状态;如果可以获取锁或者捕捉到信号则会返回
lock:结构为flock,设置记录锁的具体状态
函数返回值 :0:成功
-1:出错
4、lock 的结构:
struct flock
{
short l_type;
off_t l_start;
short l_whence;
off_t l_len;
pid_t l_pid;
}
lock 结构中每个变量的取值含义
l_type:F_RDLCK:读取锁(共享锁)
F_WRLCK:写入锁(排斥锁)
F_UNLCK:解锁
l_stat: 相对位移量(字节)
l_whence:相对位移量的起点(同lseek的whence)
SEEK_SET:当前位置为文件的开头,新位置为偏移量的大小
SEEK_CUR:当前位置为文件指针的位置,新位置为当前位置加上偏移量
SEEK_END:当前位置为文件的结尾,新位置为文件的大小加上偏移量的大小
l_len :加锁区域的长度
5、使用举例:
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
int lock_set(int fd, int type)
{
struct flock old_lock, lock;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
lock.l_type = type;
lock.l_pid = -1;
/* 判断文件是否可以上锁 */
fcntl(fd, F_GETLK, &lock);
if (lock.l_type != F_UNLCK)
{
/* 判断文件不能上锁的原因 */
if (lock.l_type == F_RDLCK) /* 该文件已有读取锁 */
{
printf("Read lock already set by %d\n", lock.l_pid);
}
else if (lock.l_type == F_WRLCK) /* 该文件已有写入锁 */
{
printf("Write lock already set by %d\n", lock.l_pid);
}
}
/* l_type 可能已被F_GETLK 修改过 */
lock.l_type = type;
/* 根据不同的type 值进行阻塞式上锁或解锁 */
if ((fcntl(fd, F_SETLKW, &lock)) < 0)
{
printf("Lock failed:type = %d\n", lock.l_type);
return 1;
}
switch(lock.l_type)
{
case F_RDLCK:
{
printf("Read lock set by %d\n", getpid());
}
break;
case F_WRLCK:
{
printf("Write lock set by %d\n", getpid());
}
break;
case F_UNLCK:
{
printf("Release lock by %d\n", getpid());
return 1;
}
break;
default:
break;
}
return 0;
}
int main(void)
{
int fd;
/* 首先打开文件 */
fd = open("hello",O_RDWR | O_CREAT, 0644);
if(fd < 0)
{
printf("Open file error\n");
exit(1);
}
/* 给文件上写入锁 */
lock_set(fd, F_WRLCK);
getchar();
/* 给文件解锁 */
lock_set(fd, F_UNLCK);
getchar();
close(fd);
exit(0);
}