首页 > 其他分享 >文件加锁

文件加锁

时间:2024-11-10 17:31:01浏览次数:1  
标签:fcntl 文件 加锁 描述符 进程 flock

文件加锁

对文件加锁是为了避免,多个进程或线程这种并发情况下,对同一个文件进行修改时造成的混乱

比如说进程A修改了文件的内容,进程B也修改了文件的内容,并且覆盖了A写的内容,然么进程A读取的内容就和预想的不同了,从而造成了混乱

对文件加锁就和信号量这些同步技术类似,只不过它是专门为文件设计的

对文件加锁的 一般步骤

  • 给文件加锁

  • 执行文件I/O

    • 在执行I/O时,当文件锁与stdio混合使用时,需要注意 缓冲区加锁解锁的时机

    比如说(假设使用stdio库),当进程A对文件加锁,写入数据,数据被存储在缓冲区中,然后解锁,此时数据并不一定会刷新到文件中,然后进程B执行同样的步骤,这就导致了,写入顺序的混乱

    为了避免这种情况,一定要注意缓冲区的情况:

    1. readwrite代替stdio
    2. 在对文件加锁之后立即刷新stdio流,并且在释放锁之前立即再次刷新这个流
    3. setbuf禁用缓冲区
  • 解锁文件使得其他进程能够给文件加锁

对整个文件加锁

flock()系统调用在整个文件上放置一个锁。待加锁的文件是通过传入 fd 的一个打开着的文件描述符来指定的。在默认情况下,如果另一个进程已经持有了文件上的一个不兼容的锁,那么 flock()会阻塞。

int flock(fd, int operation);

1

任意数量的进程可同时持有一个文件上的共享锁,但在同一个时刻只有一个进程能够持有一个文件上的互斥锁。(换句话说,互斥锁会拒绝其他进程的互斥和共享锁请求)

以下是多个进程对同一个文件加锁的兼容性

2

flock加锁是对 文件本身 作用的,也就是说,如果对指向同一个文件的不同的文件描述符加锁解锁,都只是对最终的文件进行操作

尽管flock对整个文件加锁,是很方便,但这还是影响了并发性能,也许两个进程虽然对同一个文件操作,但他们可能并不会影响对方,在这种情况下,仍然对整个文件加锁,就降低了并发性能

对文件区域加锁

使用fcntl()能够在一个文件的任意部分上放置一把锁,这个文件部分既可以是一个字节,也可以是整个文件。这种形式的文件加锁通常被称为记录加锁,但这种称谓是不恰当的,因为 UNIX 系统上的文件是一个字节序列,并不存在记录边界的概念,文件记录的概念只存在于应用程序中。

3

上图展示了使用记录锁(对文件区域加锁)对进程的同步,当进程请求访问被锁住的区域时会阻塞

fcntl(fd, cmd, &flockstr);
  • 参数:

    • fd: 待加锁文件的文件描述符
    • flockstr:定义了待获取或删除锁,也就是对锁的描述
      4

    l_type表示锁的类型---读锁、写锁、删除锁,l_whence表示文件指针的位置,l_start表示距离文件指针的偏移位置,l_len表示锁住区域的长度

    • cmd
      • F_SETLK: 非阻塞方式设置锁,非阻塞就是如果锁不兼容则会立即失败返回,而不是阻塞等待解锁
      • F_SETLKW: 阻塞方式设置锁
      • F_GETLK:检测是否能够获取flockstr指定的区域上的锁,但实际不获取这把锁

死锁

5

当两个进程锁需要访问的区域被对方锁住时,即形成一个循环时,发生死锁

锁的饿死和排队加锁请求的优先级

排队的锁请求被准予的顺序是不确定的。如果多个进程正在等待加锁,那么它们被满足的顺序取决于进程的调度。

写者并不比读者拥有更高的优先权,反之亦然。

flock和fcntl对比

锁定范围

  • flock:
    flock 锁是文件级别的锁,当一个进程对文件加锁时,锁住的是 整个文件

  • fcntl: 锁定文件的部分区域。可以在 文件的不同部分 设置不同的锁

锁定方式

  • flock
    flock 提供两种锁类型:

    • 独占锁LOCK_EX
    • 共享锁LOCK_SH

    支持解锁:LOCK_UN

  • fcntl:

    fcntl 提供三种锁类型:

    • 读锁F_RDLCK
    • 写锁F_WRLCK
    • 解锁F_UNLCK

锁的持有者

flock和fcntl都是对 文件本身(即inode项) 进行加锁,但是 flock 认为锁的持有者是 打开文件句柄(即系统文件表项),而 fcntl 认为锁的持有者是 进程(即进程文件描述符表项)

这种区别造成的影响:

  • 锁的作用范围:

    • flock: 所有指向同一个文件的文件描述符(无论是来自同一进程,还是不同进程)都会共享同一个锁

    • fcntl: 每个进程持有的文件描述符的锁状态独立于其他进程或线程。换句话说,进程可以对文件的不同区域加锁,并且这些锁是 进程局部 的,在其他进程的文件描述符中不可见

  • 锁的继承:

    • flock: 由于 flock 是 基于系统文件表项 的,因此当一个进程通过 open() 打开一个文件并加锁时,所有指向该文件的其他文件描述符(无论是由同一进程还是其他进程打开的)都会共享该锁。换句话说,flock 锁是继承的,不同的文件描述符共享同一把锁

    • fcntl: fcntl 锁是 基于文件描述符 的,因此只有对 特定进程 的文件描述符上的锁进行修改。其他进程在其自己的文件描述符上操作时,fcntl 锁对它们没有直接影响。fcntl 锁不被继承,每个进程的锁是独立的

  • 锁的释放

    • flock:当进程关闭文件时,锁会自动释放。也就是说,如果一个进程用 flock 锁住了文件并关闭了文件,锁会立即释放,其他进程无法再通过不同的文件描述符获取锁

    • fcntl:锁与进程的文件描述符绑定,不会自动释放,只有当进程关闭文件描述符,或者显式调用 fcntl 来解除锁时,锁才会释放。因此,fcntl 锁可能在进程运行期间持续存在,直到显式解除

文件关闭和文件描述符关闭不同,文件描述符关闭,可能它所指代的文件仍然保持打开状态,即 文件描述符关闭是关闭对文件的引用,而文件关闭是指文件资源的完全释放

劝告式加锁和强制式加锁

“劝告式加锁”和“强制式加锁”这两个术语通常出现在讨论并发编程、资源竞争和锁机制的场景中。它们描述了系统如何在多进程或多线程环境下对共享资源进行访问控制和管理。

1. 劝告式加锁(Advisory Locking)

特性 劝告式加锁(Advisory Locking) 强制式加锁(Mandatory Locking)
锁的强制性 非强制,其他进程可以选择是否遵守锁 强制,其他进程必须遵守锁
阻塞行为 不阻塞,进程可以自由选择是否遵守 会阻塞尝试访问锁的进程
适用场景 不需要严格同步的应用,容忍某些竞争条件 需要强同步的场景,确保数据一致性
典型应用 文件系统的 flock(),数据库中的某些实现 文件系统的 fcntl(),数据库锁
优点 灵活,减少锁的冲突,易于实现 数据一致性高,适用于关键任务
缺点 可能出现资源竞争,导致数据损坏 性能可能下降,容易死锁

标签:fcntl,文件,加锁,描述符,进程,flock
From: https://www.cnblogs.com/dylaris/p/18537269

相关文章

  • 10-文件包含、CSRF、SSRF相关练习
    1、文件包含(1)DVWA环境下去包含其他目录的任意3个文件,要求使用相对路径../../../../../(输入多个../返回系统根目录),包含账户信息文件:/etc/passwd包含账户组信息文件:/etc/group包含磁盘配置文件:/etc/fstab(2)远程文件包含使用DVWA的文件包含漏洞包含Upload-......
  • %windir% 是一个环境变量,它指向当前操作系统中 Windows 安装目录的路径。它常用于批处
    %windir%是一个环境变量,它指向当前操作系统中Windows安装目录的路径。它常用于批处理文件、命令行或者脚本中,帮助系统或用户快速定位Windows系统文件夹的路径。类似的环境变量还有很多,它们通常用于在操作系统中快速访问重要的文件夹和目录,避免硬编码路径,从而提高脚本的可移植......
  • 【python】路径与文件管理:pathlib库的现代用法
    【Python】路径与文件管理:pathlib库的现代用法在日常的Python开发中,文件和路径管理是一个常见的任务。无论是读取文件,创建目录,还是获取文件属性,都涉及到路径操作。在Python的早期版本中,我们使用os和os.path模块来处理路径,但这些方法往往显得冗长且不够直观。为了......
  • 同一个头文件既可以用于编译 DLL,也可以用于链接到 DLL 的客户端代码
    利用条件编译(#ifdefALGLIB_EXPORTS)和DLLAPI宏的设置,可以让同一个头文件既适用于DLL库的编译,也适用于依赖该DLL的客户端代码。具体来说:在编译DLL时:头文件中的DLLAPI通过条件编译定义为__declspec(dllexport),标记这些函数是要被DLL导出的。这意味着,当编译......
  • 使用configparser 读 or 写 配置文件
    config.ini文件[config]username=2024222222password=123456time=202320241num1=1id1=018819num2=1id_1=018818读取配置文件defread_ini():file='config.ini'con=configparser.ConfigParser()con.read(file,encoding='u......
  • 在Windows中,使用批处理(.bat)文件可以通过调用命令来实现自动拨号连接。以下是通过批处
    在Windows中,使用批处理(.bat)文件可以通过调用命令来实现自动拨号连接。以下是通过批处理文件实现PPPoE(拨号)连接的基本步骤:步骤1:配置拨号连接(PPPoE)在Windows中,你首先需要设置一个PPPoE拨号连接。以下是设置步骤:打开网络连接设置:点击开始菜单,输入“网络和共享中心”并打开......
  • java-文件分割
    packagesplit;importjava.io.BufferedOutputStream;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.RandomAccessFile;importjava.io.File;publicclassSplit{publicstaticvoidmain(String[]args)throwsIOException{......
  • java-文件编码
    packagecode;importjava.io.FileOutputStream;importjava.nio.file.Files;importjava.nio.file.Path;importjava.nio.file.Paths;importjava.util.*;publicclassOperation{privatestaticList<Reconstitution>sort;privatestaticbyte[]......
  • java-文件解码
    packageback;importjava.io.BufferedReader;importjava.io.FileInputStream;importjava.io.FileOutputStream;importjava.io.InputStreamReader;importjava.util.HashMap;importjava.util.Map;publicclassBack{publicstaticvoidmain(String[]arg......
  • java-文件合并
    packagemerge;importjava.io.BufferedOutputStream;importjava.io.File;importjava.io.FileOutputStream;importjava.nio.file.Files;importjava.nio.file.Path;importjava.nio.file.Paths;importjava.util.ArrayList;publicclassMerge{publicstat......