文件锁

 

Linux中为防止多个进程同时更新文件从而导致数据丢失,或者防止文件内容在未更新完毕时被读取并引发后续问题,需要某种机制,这种机制就是文件锁。在linux中多用fcntl()实施文件锁。fcntl()的功能可分为读锁和写锁两种。其中读锁又称为共享锁,它用来防止进程读取的文件记录被更改。记录内可设置多个读锁,但当有一个读锁存在的时候就不能在该记录区域设置写锁。写锁又称为排斥锁,在任何时刻只能有一个程序对文件的记录加写锁,它用来保证文件记录被某一进程更新数据的时候不被其他进程干扰,确保文件数据的正确性,同时也避免其他进程“弄脏”数据。文件记录一旦被设置写锁,就不能再设置任何锁直至该写锁解锁。

 

 

fcntl()函数

头文件:#include<unistd.h>

              #include<sys/types.h>

              #include<fcntl.h>

函数原型:int fcntl(int fd,int cmd,struct flock*lock_set);

函数参数:fd:文件描述符

                cmd:检测锁或设置锁,设置情况如下:

                1F_GETLK:检测文件锁状态,检测结果存放在第三个参数的结构体的l_type

                2F_SETLK:对文件进行锁操作,锁操作类型存放在第三个参数的结构体的l_type

                3) F_SETLKW:同F_SETLK,不过使用该参数时若不能对文件进行锁操作则会阻塞直至可以,(Wwait,等待)

                lock_set:结构体类型指针,结构体structflock需要事先设置,与第二个参数连用。

 

函数返回值:成功:0

                     失败:-1

 

 

注:struct flock成员如下:

       structflock

       {

              shortl_type;

              shortl_whence;

              off_tl_start;

              off_tl_len;

              pid_tl_pid;

       }

结构体成员说明:

       l_type:有三个参数

                     F_RDLCK:读锁(共享锁)

                     F_WRLCK:写锁(排斥锁)

                     F_UNLCK:无锁/解锁

       l_whence:相对于偏移量的起点,参数等同于fseek()lseek()中的whence参数

                     SEEK_SET:位置为文件开头位置

                     SEEK_CUR:位置为文件当前读写位置

                     SEEK_END:位置为文件结尾位置

       l_start:加锁区域在文件中的相对位移量,与l_whence的值共同决定加锁区域的起始位置

       l_len:加锁区域的长度,若为0则表示直至文件结尾EOF

       l_pid:具有阻塞当前进程的锁,其持有的进程号会存放在l_pid中,仅由F_GETLK返回

 

示例:使用fcntl()函数对文件进行锁操作。当一个进程已经打开文件并加了写锁操作,另一个文件在读写文件时发生阻塞。注:使用两个terminal运行测试程序。

示例程序如下:

/*************************************************************************

 @Author: wanghao

 @Created Time : Mon 21 May 2018 12:06:10 AMPDT

 @File Name: lock.c

 @Description:

 ************************************************************************/

#include<stdio.h>

#include<stdlib.h>

#include<unistd.h>

#include<fcntl.h>

#include<sys/types.h>

int lock_set(int fd,int type)

{

       structflock lock;

       lock.l_whence= SEEK_SET;

       lock.l_start= 0;

       /*Setfull file*/

       lock.l_len= 0;

       lock.l_type= type;

       lock.l_pid= -1;

      

       /*Judgeif it's locked*/

       fcntl(fd,F_GETLK,&lock);

 

       /*Ifthe file can't be locked, find out the reason*/

       if(lock.l_type!=F_UNLCK)

       {

              if(lock.l_type==F_RDLCK)

              {

                     printf("Thisis a ReadLock set by %d\n",lock.l_pid);

              }

              elseif(lock.l_type==F_WRLCK)

              {

                     printf("Thisis a WriteLock set by %d\n",lock.l_pid);

              }

       }

      

       /*Lockthe file*/

       lock.l_type= type;

       /*Ifthe file has been locked, the process will wait here*/

       if((fcntl(fd,F_SETLKW,&lock))<0)

       {

              printf("LockFailed:type = %d\n",lock.l_type);

              return-1;

       }

       switch(lock.l_type)

       {

              caseF_RDLCK:

                     printf("ReadLockset by %d\n",getpid());break;

              caseF_WRLCK:

                     printf("WriteLockset by %d\n",getpid());break;

              caseF_UNLCK:

                     printf("ReleaseLockby %d\n",getpid());

                     return1;

                     break;

       }

       return0;

}

int main(int argc, const char *argv[])

{

       intfd;

       if((fd=open("hello.txt",O_RDWR))<0)

       {

              perror("failto open hello.txt");

              exit(0);

       }

       printf("Thispid_no is %d\n",getpid());

       /*Lockfile*/

       lock_set(fd,F_WRLCK);

       printf("PressENTER to continue...\n");

       getchar();

       /*Unlockfile*/

       lock_set(fd,F_UNLCK);

       close(fd);

       return0;

}

                                                                                                                                                                                                                                                                         

思考:如何设置该结构体内的成员使得加锁的范围为整个文件?

答案:设置l_whenceSEEK_SETl_start0l_len0即可。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值