文件锁

Posted it8343

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了文件锁相关的知识,希望对你有一定的参考价值。

 

当多个进程都需要对同一个文件进行读写操作的时候,有时候需要确保进程在一次读写操作完
成之前,文件不被其他进程修改。文件锁机制提供了这样的同步功能。
int fcntl(int fd, int cmd, struct flock *lock);
fcntl()函数操作文件锁时 cmd 是 F_GETLK、F_SETLK 和 F_SETLKW。第三个参数是指向
struct flock 的指针,flock 结构体包含了下面的成员:
struct flock
{   
short l_type; /* 锁的类型 */   short l_whence; /* 加锁的文件区域起点偏移的基准点*/   off_t l_start; /* 加锁的文件区域起点相对l_where偏移量 */   off_t l_len; /* 加锁的文件区域长度是多少字节 */   pid_t l_pid; /* F_GETLK返回的已经对文件加锁的进程ID */ }; 文件锁有互种类型,由 flock 结构中的 l_type 指定: F_RDLCK:读锁 F_WRLCK:写锁 F_UNLCK:解锁 锁定文件的区域起点是由 l_whence 和 l_start 共同决定的,l_whence 为些准点,可以 取 SEEK_SET,SEEK_CUR,SEEK_END 中的一个,l_start 是相对基准点的偏移量。这样介绍文 件偏移的 lseek()函数的参数是一样的。 锁定文件的区域的长度由 l_len 指定,如果 l_en 为 0,表示锁定从起点开始到文件尾 的区域。 为了锁定整个文件,通常的方法是将 l_start 指定为 0,l_whence 指定为 SEEK_SET, l_len 指定为 0

技术分享图片

下面来说明一下三个 cmd 参数的作用和用法:
  F_GETLK:查看文件描述符 fd 指向的文件中,由参数 lock 描述的锁是否被另外一把锁拒绝。按照表中的兼容性规则,如果 lock描述的锁被拒绝,那么把这把锁的信息写入参数 
lock指向的结构体中。如果 lock 可以被加入,lock 参数中的 l_type 被设置为 F_UNLCK。   F_SETLK:设置参数 lock 描述的锁,如果按表的兼容性规则被拒绝加锁,则 fcntl()函数立即出错返回。此时 errno 为 EACCESS 或者 EAGAIN。   F_SETLKW:这是 F_SETLK 的阻塞版本,如果新加的锁被拒绝,那么进程被阻塞直到可以加锁。
  1 #include"common.h"
  2 
  3 /*使用 fcntl()函数来进行文件锁操作的时候,每次都要
  4 声明一个结构体并赋值,代码看上之很不整洁,因此先封装一些函数:*/
  5 int set_lock( int fd, int cmd, int type, off_t offset, int whence, off_t
  6         len )
  7 {   
  8     struct flock lock;
  9     lock.l_type = type;
 10     lock.l_start = offset;
 11     lock.l_whence = whence;
 12     lock.l_len = len;
 13     return ( fcntl( fd, cmd, &lock ) );
 14 }
 15 
 16 //利用宏定义:
 17 
 18 /* 加一把读锁 */
 19 #define  read_lock( fd, offset, whence, len )  20     set_lock( fd, F_SETLK, F_RDLCK, offset, whence, len )
 21 /* 用阻塞方式加一把读锁 */
 22 #define  readw_lock( fd, offset, whence, len )  23     set_lock( fd, F_SETLKW, F_RDLCK, offset, whence, len )
 24 /* 加一把写锁 */
 25 #define  write_lock( fd, offset, whence, len )  26     set_lock( fd, F_SETLK, F_WRLCK, offset, whence, len )
 27 /* 用阻塞方式加一把写锁 */
 28 #define  writew_lock( fd, offset, whence, len )  29     set_lock( fd, F_SETLKW, F_WRLCK, offset, whence, len )
 30 /* 解锁 */
 31 #define  un_lock( fd, offset, whence, len )  32     set_lock( fd, F_SETLK, F_UNLCK, offset, whence, len )
 33 
 34 
 35 /*用这五个函数,可以方便的对某个文件区域进行加锁和解锁*/
 36 
 37 
 38 /*测试一把锁的函数*/
 39 pid_t test_lock(int fd, int type, off_t offset, int whence, off_t len )
 40 {
 41     struct flock lock;
 42     lock.l_type = type;
 43     lock.l_start = offset;
 44     lock.l_whence = whence;
 45     lock.l_len = len;
 46     if( fcntl( fd, F_GETLK, &lock ) == -1 ){
 47         perror( "fcntl" );
 48         return -1;
 49     }
 50     if( lock.l_type == F_UNLCK ){
 51         return 0;
 52     }
 53     return lock.l_pid;
 54 }
 55 /*打印函数*/
 56 void  pid_printf( char *format, ... )
 57 {
 58     va_list ap;/*va在这里是variable-argument(可变参数)的意思*/
 59     va_start( ap, format );
 60     printf("[%d]:", getpid() );
 61     vprintf( format, ap );
 62     va_end(ap);
 63 }
 64 
 65 int main( int argc, char **argv )
 66 {
 67     int fd;
 68     pid_t pid;
 69     pid_t lpid;
 70     /*创建一个文件*/
 71     fd = creat( "./file1", 0640 );//(0640文件属性)
 72     if( fd == -1 )
 73     {
 74         perror( "create file1 error!" );
 75     }
 76     pid_printf("./file1 created, fd = [%d]
", fd);
 77     /*给文件加写锁*/
 78     pid_printf("lock file  now
");
 79     write_lock( fd, 0, SEEK_SET, 0 );//锁定整个文件(写)
 80     /*派生进程*/
 81     pid = fork();
 82     if( pid == 0 )
 83     {
 84         /*子进程打开文件*/
 85         fd = open( "./file1", O_RDWR );
 86         if( fd == -1 )
 87         {
 88             perror( "open file1 error!" );
 89         }
 90         /*一直等到文件解锁*/
 91         while( 1 )
 92         {
 93             lpid = test_lock( fd, F_RDLCK, 0, SEEK_SET, 0 );
 94             if( lpid > 0 )
 95             {
 96                 pid_printf("process [%d] locked file1
",lpid );
 97             }else if( lpid == 0 )
 98             {
 99                 pid_printf("file1 unlocked
");
100                 break;
101             }
102             else
103             {
104                 break;
105             }
106             sleep(1);
107         }
108         close( fd );
109     }
110  else if( pid != -1 )
111     {
112         sleep(3);
113         pid_printf("Unlock write lock of file1 now
");
114         /*给文件解锁*/
115         un_lock( fd, 0, SEEK_SET, 0 );
116         /*等待子进程退出*/
117         waitpid(pid,NULL,0);
118     }else
119     {
120         printf("There was an error with forking!
");
121     }
122     close( fd );
123     return 0;
124 }
125                            

运行结果:

[22792]:./file1 created, fd = [3]
[22792]:lock file  now
[22793]:process [22792] locked file1
[22793]:process [22792] locked file1
[22793]:process [22792] locked file1
[22792]:Unlock write lock of file1 now
[22793]:file1 unlocked

 



以上是关于文件锁的主要内容,如果未能解决你的问题,请参考以下文章

LockSupport.java 中的 FIFO 互斥代码片段

读写锁 与 互斥锁

互斥锁 & 共享锁

并发技术12线程锁技术的使用

java并发线程锁技术的使用

ReentrantReadWriteLock场景应用