多进程文件锁

多进程文件锁一、多进程文件锁当多个用户共同使用、操作一个文件的情况下,这时,Linux通常采用的方法是给文件上锁,来避免共享的资源产生竞争的状态1.文件锁方式对当前读写文件进行加锁处理,简单说下两种加锁方式:flock():文件级别的锁,针对整个文件进行加锁。flock用于对文件施加建议性锁。fcntl()函数:段级别的锁,能够针对文件的某个部分进行加锁。而fcntl不仅可以施

大家好,又见面了,我是你们的朋友全栈君。

一、多进程文件锁

当多个用户共同使用、操作一个文件的情况下,这时,Linux通常采用的方法是给文件上锁,来避免共享的资源产生竞争的状态

1.文件锁方式

对当前读写文件进行加锁处理,简单说下两种加锁方式:

flock():文件级别的锁,针对整个文件进行加锁。 flock用于对文件施加建议性锁。

fcntl()函数:段级别的锁,能够针对文件的某个部分进行加锁。 而fcntl不仅可以施加建议性锁,还可以施加强制性锁,还能对文件的某一记录进行上锁,也就是记录锁。

2.文件锁类型

文件锁包括建议性锁和强制性锁。

 建议性锁要求每个上锁文件的进程都要检查是否有锁存在,并且尊重已有的锁。在一般情况下,内核和系统都不使用建议性锁。

强制性锁是由内核执行的锁,当一个文件被上锁进行写入操作的时候,内核将阻止其它任何文件对其进行读写操作。采用强制性锁对性能的影响很大,每次读写操作都必须检查是否有锁存在。

记录锁又分为读取锁和写入锁

读取锁又称共享锁,能使多个进程都在文件的同一部分建立读取锁。

写入锁又称为排斥锁,在任何时刻只能有一个进程在文件的某个部分建立写入锁

在文件的同一部分不能同时建立读取锁和写入锁。

3.fcntl函数说明

(1)fcntl函数格式  具体的知识可以参看unix环境高级编程

Fcntl函数语法要点:

所需头文件:#include<sys/types.h>

                     #include<unistd.h>

                     #include<fcntl.h>

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

函数传入值:fd:文件描述符

                     Cmd:F_DUPFD:复制文件描述符

F_GETFD:获得fd的close-on-exec标志,若标志未设置,则文件经过exec函数之后仍保持打开状态。

F_SETFD:设置close-on-exec标志,该标志以参数arg的FD_CLOEXEC位决定。

F_GETFL:得到open设置的标志

F_SETFL:改变open设置的标志

F_GETFK:根据lock描述,决定是否上文件锁

F_SETFK:设置lock描述的文件锁

F_SETLKW:这是F_SETLK的阻塞版本(命令名中的W表示等待(wait))。如果存在其它锁,则调用进程睡眠;如果捕捉到信号则睡眠中断

     这三种是在文件锁时cmd 使用的三种命令

F_GETOWN:检索将收到SIGIO和SIGURG信号的进程号或进程组号

F_SETOWN:设置进程号或进程组号

                     Lock:结构为flock,设置记录锁的具体状态

函数返回值:成功:0

                     -1:出错

Lock的结构如下所示:

Struct flock{

Short l_type;

Off_t l_start;

Short l_whence;

Off_t l_len;

Pid_t l_pid;

}

Lock结构变量取值:

L_type:F_RDLCK:读取锁(共享锁)

              F_WRLCK:写入锁(排斥锁)

              F_UNLCK:解锁

L_stat:相对位移量(字节)

L_whence:相对位移量的起点(同lseek的whence):SEEK_SET:当前位置为文件开头,新位置为偏移量的大小

                                    SEEK_CUR:当前位置为文件指针位置,新位置为当前位置加上偏移量

                                    SEEK_END:当前位置为文件的结尾,新位置为文件的大小加上偏移量大小

L_len:加锁区域长度

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



(2)fcntl 使用实例


  下面首先给出了使用fcnt函数的文件记录锁功能的代码实现。在该代码中,首先给flock结构体的对应

赋予相应的值。

  接着调用两次fcntl函数。用F_GETLK命令判断是否可以进行flock所描述的锁操作:若可以进行,则flock

结构体的l_type会被设置为F_UNLCK,其他域不变;若不行,则l_pid被设置为拥有文件锁的进程号,其他域不变。


   用F_SETLK和F_SETLKW命令设置flock结构所描述的锁操作,后者是前者的阻塞版。

   当第一次调用fcntl时,使用F_GETLK命令获得当前文件被上锁的情况,由此可以判断能不能上锁操作;当第二次调用fcntl时,使用F_SETLKW命令对指定文件进行上锁/解锁操作。因为F_SETLKW命令是阻塞式操作,因此当不能把上锁/解锁操作进行下去时,运行被阻塞,直到能够进行操作为止。



实例说明

  开启两个终端,在两个终端上同时运行./write_lock 程序,

  当为写入锁,同一时刻只能有一个写入锁存在,

  同一时刻只能一个进程对同一个文件写

  注意运行的结果

  

  1.首先运行右边终端中的程序,提示 write lock set by 3638  进程号

  2.容纳后运行左边终端中的程序,提示 write lock already set by 3683

  3.右边终端敲  回车  ,释放读锁

  4.左边终端敲  回车  , 提示 write lock set by 3639

 

set_lock.h

  1. #ifndef _LOCK_SET_H
  2. #define _ LOCK_SET_H
  3. #include<sys/types.h>
  4. #include<unistd.h>
  5. #include<fcntl.h>
  6. #include<stdio.h>
  7. int lock_set(int fd,int type);
  8. #endif

set_lock.c

  1. /* lock_set.c */
  2. #include“lock_set.h”
  3. int lock_set(int fd, int type)
  4. {
  5.     struct flock old_lock, lock;
  6.     lock.l_whence = SEEK_SET;
  7.     lock.l_start = 0;
  8.     lock.l_len = 0;
  9.     lock.l_type = type;
  10.     lock.l_pid = –1;
  11.     
  12.     /* 判断文件是否可以上锁 */
  13.     fcntl(fd, F_GETLK, &lock);
  14.     if (lock.l_type != F_UNLCK)
  15.     {
  16.         /* 判断文件不能上锁的原因 */
  17.         if (lock.l_type == F_RDLCK) /* 该文件已有读取锁 */
  18.         {
  19.             printf(“Read lock already set by %d\n”, lock.l_pid);
  20.         }
  21.         else if (lock.l_type == F_WRLCK) /* 该文件已有写入锁 */
  22.         {
  23.             printf(“Write lock already set by %d\n”, lock.l_pid);
  24.         }            
  25.     }
  26.     
  27.     /* l_type 可能已被F_GETLK修改过 */
  28.     lock.l_type = type;
  29.     /* 根据不同的type值进行阻塞式上锁或解锁 */
  30.     if ((fcntl(fd, F_SETLKW, &lock)) < 0)
  31.     {
  32.         printf(“Lock failed:type = %d\n”, lock.l_type);
  33.         return 1;
  34.     }
  35.         
  36.     switch(lock.l_type)
  37.     {
  38.         case F_RDLCK:
  39.         {
  40.             printf(“Read lock set by %d\n”, getpid());
  41.         }
  42.         break;
  43.         case F_WRLCK:
  44.         {
  45.             printf(“Write lock set by %d\n”, getpid());
  46.         }
  47.         break;
  48.         case F_UNLCK:
  49.         {
  50.             printf(“Release lock by %d\n”, getpid());
  51.             return 1;
  52.         }
  53.         break;
  54.         default:
  55.         break;
  56.     }/* end of switch */
  57.     return 0;
  58. }

write_lock.c

  1. /* write_lock.c */
  2. #include <unistd.h>
  3. #include <sys/file.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include “lock_set.h”
  9. int main(void)
  10. {
  11.     int fd;
  12.     /* 首先打开文件 */
  13.     fd = open(“hello”, O_RDWR | O_CREAT, 0644);
  14.     if(fd < 0)
  15.     {
  16.         printf(“Open file error\n”);
  17.         exit(1);
  18.     }
  19.     /* 给文件上写入锁 */
  20.     lock_set(fd, F_WRLCK);
  21.     getchar();
  22.     /* 给文件解锁 */
  23.     lock_set(fd, F_UNLCK);
  24.     getchar();
  25.     close(fd);
  26.     return 0;
  27. }

4.flock函数说明

简单介绍下flock()函数:

 
 
 
 

表头文件  #include

  定义函数  int flock(int fd,int operation);

  函数说明  flock()会依参数operation所指定的方式对参数fd所指的文件做各种锁定或解除锁定的动作。此函数只能锁定整个文件,无法锁定文件的某一区域。

  参数  operation有下列四种情况:

   LOCK_SH 建立共享锁定。多个进程可同时对同一个文件作共享锁定。

  LOCK_EX 建立互斥锁定。一个文件同时只有一个互斥锁定。

  LOCK_UN 解除文件锁定状态。

   LOCK_NB 无法建立锁定时,此操作可不被阻断,马上返回进程。通常与LOCK_SH或LOCK_EX 做OR(|)组合。

  单一文件无法同时建立共享锁定和互斥锁定,而当使用dup()或fork()时文件描述词不会继承此种锁定。

  返回值  返回0表示成功,若有错误则返回-1,错误代码存于errno。

为了更好的移植性,对于文件的打开与关闭我选择了fopen和fclose的组合,但flock的第一个参数要求的是int类型的文件描述符。这里对fopen返回的FILE类型的文件指针进行转换,转换为int型的文件描述符(假设open函数返回的文件描述符为fd,而fopen返回的文件指针为*fp,则fd等价于fp->_fileno).


下面为两个进程的实例:

int main(void)

{

    FILE *fp = NULL;

    int i = 20; 

    

    if ((fp = fopen(“./file_lock.test”, “r+b”)) == NULL) //打开文件

        printf(“file open error!\n”);

    if (flock(fp->_fileno, LOCK_EX) != 0) //给该文件加锁

        printf(“file lock by others\n”);

    while(1) //进入循环,加锁时间为20秒,打印倒计时

    {   

        printf(“%d\n”, i–);

        sleep(1);

        if (i == 0)

            break;

    }   

    fclose(fp); //20秒后退出,关闭文件

    flock(fp->_fileno, LOCK_UN); //文件解锁

    return 0;

 

}


 

int main(void)

{

    FILE *fp = NULL;

    int i = 0;

    

    if ((fp = fopen(“./file_lock.test”, “r+b”)) == NULL) //打开文件

        printf(“file open error!\n”);

    flock(fp->_fileno, LOCK_EX); //文件加锁

    while(1) //进入循环

    {   

        printf(“%d\n”, i++);

        sleep(1);

    }   

    fclose(fp); //关闭文件

    flock(fp->_fileno, LOCK_UN); //释放文件锁

    return 0;

 

}


首先运行file1.c,紧接着运行file2.c(运行file1.c后20秒内要运行file2.c否则看不到现象)
现象是:file1.c执行起来以后,开始倒计时。此时运行file2.c会阻塞在加锁处。当file1.c运行20秒后关闭文件,并释放文件锁后,file2.c会开始运行。

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/153495.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长

相关推荐

  • 利用#ZipLib,完成C#下的解压缩「建议收藏」

    利用#ZipLib,完成C#下的解压缩「建议收藏」 ICSharpCode.SharpZipLib.dll是一个压缩的类库,似乎不是微软提供的1.BZip2    加入ICSharpCode.SharpZipLib.dll的引用,在#Develop的安装目录下的/SharpDevelop/bin目录下。然后在程序中使用using语句把BZip2类库包含进来。压缩:使用BZip2的静态方法Compress。    它的第一个参数是所要压缩

    2022年7月26日
  • Random之nextInt函数「建议收藏」

    Random之nextInt函数「建议收藏」1java中有一个类用于生成随机数字的:Random。该类的nextInt(intn)函数表示随机生成0~n之间的整数。如:intb=newRandom().nextInt(100);//0~参数之间,包括0,不包括参数本身System.out.println(b);2Random的nextInt(intn)生成的随机整数范围是0到n之间,不包括n。所以以后如果想要

    2022年7月22日
  • 常用几种数据库对比

    常用几种数据库对比

    2021年6月9日
  • 【《重构 改善既有代码的设计》学习笔记3】代码的坏味道[通俗易懂]

    【《重构 改善既有代码的设计》学习笔记3】代码的坏味道本篇文章的内容来自《重构 改善既有代码的设计》一书学习笔记整理并且加上自己的浅显的思考总结!知道重构的原则和何时进行重构,那本篇就总结一些代码的坏味道,知道具体从哪些方面来进行重构。kent Beck提出用 味道来形容重构的时机。作者说:何时必须重构没有一个精确的衡量标准,任何量度规矩也比不上一个见识广博者的直觉。如果没有广博的见识…

    2022年2月27日
  • 银行家算法C++实现

    银行家算法C++实现网上有很多银行家算法的源代码,下面是本人自己写的,基本算法模型参考教材。介绍银行家算法(Banker’sAlgorithm)是一个避免死锁(Deadlock)的著名算法,是由艾兹格·迪杰斯特拉(EdsgerWybeDijkstra)在1965年为T.H.E系统设计的一种避免死锁产生的算法。它以银行借贷系统的分配策略为基础,判断并保证系统的安全运行。背景简介在银行中…

    2022年7月22日
  • FTP协议讲解

    FTP协议讲解FTP概述文件传输协议(FTP)作为网络共享文件的传输协议,在网络应用软件中具有广泛的应用。FTP的目标是提高文件的共享性和可靠高效地传送数据。在传输文件时,FTP客户端程序先与服务器建立连接,然后向服务器发送命令。服务器收到命令后给予响应,并执行命令。FTP协议与操作系统无关,任何操作系统上的程序只要符合FTP协议,就可以相互传输数据。本文主要基于LINUX平台,对FTP…

    2022年6月21日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号