记录锁 详解

记录锁的功能:当某个进程正在读或者修改某个文件的某个部分的时候,记录锁可以阻止其他进程在同一时间对这部分文件的访问修改。

                         

        早期的伯克利版本只支持flock函数,改函数锁只能锁住整个文件,不能锁文件中的某一部分文件;SVR3通过fcntl函数添加了记录锁的功能,在此基础上构造了lockf 函数,这些函数允许调用者锁住文件中的任意部分,长至整个文件,短至文件中的一个字节。

 

                                    fcntl函数构建记录锁

        

                                    #include <fcntl.h>

                                    int   fcntl(int  filedes,   int   cmd,   ../* struct  flock  *flockptr);

                                    返回值:成功则依赖于cmd的值,失败全都返回-1;

 

                                   对于记录锁,cmd的值是 F_GETLK  、 F_SETLK   、 F_SETLKW 

                                   flock 结构体:

                                   struct   flock

                                  {

                                       short   l_type;  /**锁的类型: F_RDLCK(读锁) 、F_WRLCK(写锁) 、F_UNLCK(解锁)  ,读锁与读锁之间不阻塞、读锁与写锁阻塞、写锁与写锁阻塞*/

                                       off_t   l_start;       /****偏移量:从whence位置开始***********/

                                       short  l_whence;  /***偏移的首位置:SEEK_SET(文件头)、SEEK_CUR(文件的当前位置)、SEEK_END(文件尾)********/

                                       off_t   l_len;        /******需要锁住文件中的长度,0表示锁住整个文件******/

                                       pid_t  l_pid;     /******returned   with F_GETLK******/

                                      };

 

       F_GETLK:判断由flockptr所描述的锁是否被另外一把锁阻塞,如果有,则阻止创建由flockptr所描述的锁,并把该现有锁的信息写到flockptr指向的结构体中;如果不存在,则把l_type设置为F_UNLCK,其他信息不变。(所以,F_GETLK常用来判断文件是否加了锁,若l_type == F_UNLCK 则表示没有加锁,反之则加了锁。F_GETLK并不用来加锁,只是作为一种判断)。

              struct flock fl;
 30         fl.l_type = F_WRLCK;
 31         fl.l_whence = whence;
 32         fl.l_start = offset;
 33         fl.l_len = len;
 34
 35         fcntl(fd, F_GETLK, &fl);
 36         if(fl.l_type == F_UNLCK)
 37         {//表示没有加写锁
 38                 return 0;
 39         }
 40         return 1;

      

       F_SETLK:试图创建一把由flockptr所描述的锁,当文件之前如果已经加过锁了,则立即出错返回,否则加锁。

 

       F_SETLKW:这是F_SETLK的阻塞版本(命令中的W表示等待),如果已加锁则等待直到解锁在加锁,如果没有加锁则直接加锁。

    

       F_GETLK先判断是否加锁,F_SETLKW再来加锁,这不是一个原子操作,有时间窗口,因此不能保证在F_GETLK和F_SETLKW之间不会被另一个进程插入并建立一把相关的锁。所以如果不希望这种情况发生,应使用F_SETLK,通过对其返回结果测试来判断是否建立了所需要求的锁。

 

   //读锁
  7 #define    read_lock(fd, offset, whence, len)    lock_reg(fd, F_RDLCK, offset, whence, len)  /*****宏定义*******/
  9
 10 //写锁
 11 #define write_lock(fd, offset, whence, len)     lock_reg(fd, F_WRLCK, offset, whence, len)
 13

     //解锁
 14 #define unlock(fd, offset, whence, len)          lock_reg(fd, F_UNLCK, offset, whence, len)     
 16
 17 //设置锁
 18 static int inline lock_reg(int fd, short type, off_t offset, short whence,     off_t len)
 19 {
 20         struct flock fl;
 21         fl.l_type = type;
 22         fl.l_whence = whence;
 23         fl.l_start = offset;
 24         fl.l_len = len;
 25         return fcntl(fd, F_SETLKW, &fl);
 26 }

 加锁应遵循两个原则以防止死锁的情况出现:

1、不能加两次锁。

2、两个进程加锁的顺序一致,以防两个进程相互等待对方持有并锁定的资源。

 

锁的隐含继承和释放:

1、当一个进程结束时,其建立的所有锁全都释放。

2、任何时刻关闭一个描述符时,则该进程通过这个描述符可以引用的文件上的任何一把锁都释放。

3、由fork产生的子进程不继承父进程所设置的锁。

4、在执行exec后,新程序可以继承原执行程序的锁。

 

 

在文件尾端加锁或者解锁时要特别小心,采用SEEK_END和SEEK_CUR是可能不断变化的,所以们最好采用SEEK_SET,使用绝对偏移,否则则应时刻记住当前偏移量和文件尾端的位置。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值