/*我们可以简单的使用系统函数实现对文件的I/O操作,但是,Linux是多任务的系统,当一个共享文件被多个用户访问时,该如何使用的时候,该如何避免共享时所发生的资源竞争呢?
文件上锁包括建议性上锁和强制性上锁,建议性上锁要求每个上锁的进程都要检查是否有锁的存在,并且尊重已有的锁,内核和系统都不使用建议性上锁,强制性锁是由内核执行的锁。
在Linux中,实现上锁的系统调用有lock,和fcntl,lock用于对文件进行建议性上锁,fcntl不仅可以进行建议性上锁还可以施加强制性上锁。同时,fcntl还可以对文件的某一记录进行上锁,也就是记录锁。
记录锁又可以分为读取锁和写入锁,读取锁又称为共享锁,它能使用多个进程都能在文件的同一部分建立读取锁,而写入锁又称为排斥锁,任何时候只能有一个进程在文件的某个部分建立写入锁。
当然,在同一文件的同一位置,不能同时建立读取锁和写入锁。
fcntl系统调用不仅仅用于文件上锁,它还可以查看或这设置文件的一些相关信息。
*/
我们来看一下lock的结构
struct flock
{
short l_type; //锁的类型
/*
F_RDLCK 读取锁(共享锁)
F_WRLCK 写入锁(排斥锁)
F_UNLCK 解锁
*/
off_t l_start;//相对位移量
short l_whence;//相对位移量的起点
/*
SEEK_SET 当前位置为文件的开头,新的位置为偏移量的大小
SEEK_CUR 当前位置为文件指针的位置,新的位置为当前位置加上偏移量的大小
SEEK_END 当前的位置为文件的末位,新的位置为当前位置加上偏移量
*/
off_t l_len;//加锁区的长度
pid_t l_pid;//进程ID
}
fcntl 系统调用语法:
1.头文件:
#include
#include
#include
2.函数的功能:
对文件上锁,以及进程相关的控制
3.函数原型:
int fcntl(int fd,int cmd,struct flock *lock);
4.参数形式:
fd -- 文件描述符
cmd -- 命令
lock -- 设置记录锁的具体状态信息
5.返回值:
成功返回0,有错误发生是返回1
6.备注:
给整个文件加锁的时候,通常是将l_start 设为0,l_whence为SEEK_SET,l_len 设为0
7.说明CMD:
F_DUPFD -- 复制文件描述符
F_GETFD -- 获得文件描述符close-on-exec标志
F_SETFD -- 设定文件爱你描述符close-on-exec标志
F_GETFL -- 得到open()的参数flags
F_SETFL -- 设置open()的参数flags
F_GETLK -- 根据LOCK的描述,决定是否上文件锁
F_SETLK -- 设置LOCK描述的文件锁
F_SETLKW -- F_SETLK的阻塞版本,W表式等待,如果存在其他的锁,则调用进程睡眠,如果捕捉到信号则睡眠中断
#include
#include
#include
#include
#include
#include
void lock_set(int fd,int type)
{
struct flock lock;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
while(1)
{
lock.l_type = type;
if(fcntl(fd,F_SETLK,&lock) == 0)
{
if(lock.l_type == F_RDLCK)
{
printf("进程%d给文件加的锁是读取锁\n",getpid());
}
else
{
if(lock.l_type == F_WRLCK)
{
printf("进程%d给文件加的锁是写入锁\n",getpid());
}
else
{
if(lock.l_type == F_UNLCK)
{
printf("强制释放解锁%d\n",getpid());
}
}
}
return ;
}
fcntl(fd,F_GETLK,&lock);
if(lock.l_type != F_UNLCK)
{
if(lock.l_type == F_RDLCK)
printf("进程%d给文件已经被上读取锁\n",lock.l_pid);
if(lock.l_type == F_WRLCK)
printf("进程%d给文件已经被上写入锁\n",lock.l_pid);
getchar();
}
}
}
int main()
{
int fd;
fd = open("/home/test.txt",O_RDWR|O_CREAT,0666);
if(fd<0)
{
perror("Open ERROR!");
exit(1);
}
lock_set(fd,F_WRLCK);
getchar();
lock_set(fd,F_UNLCK);
getchar();
close(fd);
exit(0);
}