• Linux系统文件I/O编程(二)---文件锁函数


    上一节:http://blog.csdn.net/mybelief321/article/details/8989755讲述的5个基本函数函数open()、read()、write()、lseek()和close()实现的文件的打开、读/写等操作,本节将讨论在文件已经共享的情况下如何操作,也就是当多个用户共同使用、操作一个文件的情况。这时,Linux通常采用的方法是给文件上锁,来避免共享的资源产生竞争的状态。

       文件锁包括建议性锁和强制性锁。建议性锁要求每个上锁文件的进程检查是否有锁存在,并且尊重已有的锁。在一般情况下,内核和系统都不使用建议性锁。强制性锁是由内核执行的锁,当一个文件被上锁执行写入操作时,内核将阻止其他任何文件对其进行读写操作。采用强制性锁对性能影响很大,每次读写都必须检查是否有锁存在。

       在Linux中,实行文件上锁的函数有lockf()和fcntl(),其中lockf()用于对文件施加建议性锁,而fcntl()不仅可以施加建议性锁,还可以施加强制性锁。同时,fcntl()还能对文件的某一记录上锁,也就是记录锁。

       记录锁又可分为读取锁和写入锁,其中读取锁又称为共享锁,它能够使多个进程都能在文件的同一部分建立读取锁。而写入锁又称为排斥锁,在任何时刻只能有一个进程在某个部分建立写入锁。当然,在文件的同一部分不能同时建立读取锁和写入锁。

       fcntl()函数具有很丰富的功能,它可以对已打开的文件描述符进行各种操作,不仅包括管理文件锁,还包括获得设置文件描述符和文件描述符标志、文件描述符的复制等很多功能!这一次我先学习一下fcntl()函数建立文件锁的方法,关于它的另外的用法...先学会了这个再说吧!

    fcntl()函数格式

       

       表1中的lock是一个flock结构体,结构如下:

       

       上图中的 off_t 就是数据类型 long int ;pid_t 就是数据类型  int,不懂这里有解释:点此解释

       那么这个结构体lock中每个变量的取值含义如下表2

      

    基础实验

       本实验主要是为了练习一下fcntl()函数的文件记录锁的功能。下面首先给出了使用fcntl(0函数的文件记录锁功能的代码实现。

       在该代码中,首先给flock结构体的对应位赋予相应的值。接着调用两次fcntl()函数,使用F_GETLK命令判断是否可以进行flock结构体所描述的锁操作:若可以进行,则flock结构的l_type会被设置为F_UNLCK,其他域不变;若不可进行,则l_pid被设置为拥有文件锁的进程号,其他域不变。

       用F_SETLK和F_SETLKW命令设置flock结构所描述的锁操作,后者是前者的阻塞版。
       当第一次调用fcntl()时,使用F_FETLK命令获得当前文件被上锁的情况,由此可以判断能不能进行上锁操作;当第二次调用fcntl()时,使用F_SETLKW命令对指定文件进行上锁/解锁操作。因为F_SETLKW命令是阻塞式操作,所以,当不能把上锁/解锁操作进行下去时,运行会被阻塞,直到能够进行操作为止。

      本次实验代码均上传到了网站,请自行下载:点此下载

       文件记录锁的功能代码具体如下:

    /*lock_set.c*/
    int lock_set(int fd,int type)
    {
     struct flock old_lock,lock;  /*定义flock结构体*/
     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 ",lock.l_pid);
      } 
      else if(lock.l_type==F_WRLCK) /*该文件已经有写入锁 */
      {
        printf("Write lock already set by %d ",lock.l_pid);     
      }
     }
     
     /*l_type 可能在执行完上述判断后被修改了*/
     lock.l_type=type;
     /*根据不同的type值进行阻塞式上锁或解锁*/
     if((fcntl(fd,F_SETLKW,&lock))<0)
     {
      printf("Lock failed:type=%d ",lock.l_type);
      return 1; 
     }
     switch(lock.l_type)
     {
      case F_RDLCK:
      {
       printf("Read lock set by %d ",getpid());/*getpid()用来得到当前的进程号*/ 
      } 
      break;
      case F_WRLCK:
      {
       printf("Write lock set by %d ",getpid());
      } 
      break;
      case F_UNLCK:
      {
       printf("Release lock set by %d ",getpid());
       return 1;
      } 
      break;
      default:break;      
     }  /*end of switch*/
     return 0;
    }

        下面的代码是文件写入锁的测试用例,这里首先创建一个hello.c文件,然后对其上锁,最后释放写入锁。代码如下所示:

    /*write_lock.c*/

    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<sys/types.h>
    #include<sys/stat.h>
    #include<sys/file.h>
    #include"lock_set.c"

    int main(void)
    {
     int fd;
     
     /*首先打开文件*/
     fd=open("/home/song/hello.c",O_RDWR|O_CREAT,0644);
     if(fd<0)
     {
      printf("Open file error! ");
      exit(1); 
     }
     
     /*给文件上写入锁*/
     lock_set(fd,F_WRLCK);
     getchar();  /*当用户输入任意键后,程序继续执行,否则等待*/
     /*给文件解锁*/
     lock_set(fd,F_UNLCK);
     getchar();
     close(fd);  /*关闭该文件*/
     exit(0);
    }

         文件结构如下图:

         

        使用命令:gcc write_lock.c -o write_lock编译

        

        为了使程序有较大的灵活性,我们的程序中采用文件上锁后由用户输入任意键使程序继续执行。为了更好地显示写入锁的作用,在这里我们开两个终端,并且在终端上同时运行该程序,以达到多个进程操作一个文件的效果。首先运行终端1,请注意终端2中的第一句话

         

          

        由上图可见,写入锁为互斥锁,同一时刻只能有一个写入锁存在

        接下来测试文件读取锁,原理和上边一样,代码如下

    /*read_lock.c*/

    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<sys/types.h>
    #include<sys/stat.h>
    #include<sys/file.h>
    #include"lock_set.c"

    int main(void)
    {
     int fd;
     
     /*首先打开文件*/
     fd=open("/home/song/hello.c",O_RDWR|O_CREAT,0644);
     if(fd<0)
     {
      printf("Open file error! ");
      exit(1); 
     }
     /*给文件上读取锁*/
     lock_set(fd,F_RDLCK);
     getchar();  /*当用户输入任意键后,程序继续执行,否则等待*/
     /*给文件解锁*/
     lock_set(fd,F_UNLCK);
     getchar();  /*当用户输入任意键后,程序继续执行,否则等待*/  
     close(fd);  /*关闭该文件,释放锁*/
     exit(0); 

    }

        在两个终端下运行的结果如下图:

        

        

        与写入锁的运行结果比较,可有看出,读取锁为共享锁,当进程7170已设置读取锁后,进程7294仍然可以设置读取锁。

    总结:这一节讲了文件锁的问题,那么咱们再来想一下:为什么要有文件锁?原因就是当文件共享,也就是多个用户共同使用、操作一个文件的情况,为了避免共享的资源产生竞争的状态,Linux就采用了给文件上锁的方法。

  • 相关阅读:
    Codeforces Round #567 (Div. 2) B. Split a Number
    es界面的分组,求平均值的操作
    es界面的查询命令
    es界面的crud
    WebStorm中自定义文档注释模板
    Vue 正确理解mounted、beforeUpdate、updated三个钩子函数的关系
    oracle分析函数
    vue中时间格式的处理
    vue-router params和query的区别
    vue中的深拷贝理解和实现
  • 原文地址:https://www.cnblogs.com/tkid/p/3639168.html
Copyright © 2020-2023  润新知