linux 文件锁

建议锁,强制锁,记录锁的概念

建议锁:
        如果某一个进程对一个文件持有一把锁之后,其他进程仍然可以直接对文件进行操作(open, read, write)而不会被系统禁止,即使这个进程没有持有锁。只是一种编程上的约定。建议锁只对遵守建议锁准则的进程生效(程序在操作前应该自觉的检查所的 状态之后才能进行后续操作)
强制锁:
        试图实现一套内核级的锁操作。当有进程对某个文件上锁之后,其他进程会在open、read 或 write 等文件操作时发生错误。
记录锁:
        只对文件中自己所关心的那一部分加锁。记录锁是更细粒度的文件锁。记录锁存在于文件结构体中,并不与文件描述符相关联,会在进程退出时候被释放掉。

fcntl,flock,lockf 之间的区别

        这三个函数的作用都是给文件加锁,那它们有什么区别呢?首先 flock 和 fcntl 是系统调用,而 lockf 是库函数。lockf 实际上是对 fcntl 的封装,所以 lockf 和 fcntl 的底层实现是一样的,对文件加锁的效果也是一样的。后面分析不同点时大多数情况是将 fcntl 和 lockf 放在一起的。下面首先看每个函数的使用,从使用的方式和效果来看各个函数的区别。

flock 函数

头文件:
#include <sys/file.h>
函数原型:
int flock(int fd, int operation); // 在 fd 指定的打开文件上应用或删除建议锁
函数描述:
        flock()会依参数 operation 所指定的方式对参数 fd 所指的文件做各种锁定或解除锁定的动作。此函数只能锁定整个文件,无法锁定文件的某一区域。
参数描述:
        fd:文件描述符
        operation:属性参数选项
                LOCK_SH:共享锁
                LOCK_EX:排他锁或独占锁
                LOCK_UN:解锁
                LOCK_NB:使用非阻塞方式上锁,无法建立锁定时,此操作可不被阻断,马上返回进程。通常与 LOCK_SH 或 LOCK_EX 以或(OR)方式组合使用,因为单一文件无法同时建立共享锁定和互斥锁定。
返回值:
        返回 0 表示成功,若有错误则返回-1,错误代码存于 errno。
用法描述:
        flock 只要在打开文件后,需要对文件读写之前 flock 一下就可以了,用完之后再flock 一下,前面加锁,后面解锁。
        进程使用 flock 尝试锁文件时,如果文件已经被其他进程锁住,进程会被阻塞直到锁被释放掉,或者在调用 flock 的时候,采用 LOCK_NB 参数,在尝试锁住该文件的时候,发现已经被其他服务锁住,会返回错误。
        flock 锁的释放非常具有特色,即可调用 LOCK_UN 参数来释放文件锁,也可以通过关闭 fd 的方式来释放文件锁(flock 的第一个参数是 fd),意味着 flock 会随着进程的关闭而被自动释放掉
特点:
         关于 flock 函数,首先要知道 flock 函数只能对整个文件上锁,而不能对文件的某一部分上锁,这是于 fcntl/lockf 的第一个重要区别,后者可以对文件的某个区域上锁。 其次,flock 只能产生劝告性锁。我们知道,linux 存在强制锁(mandatory lock)和劝告锁(advisory lock)。再次,flock 和 fcntl/lockf 的区别主要在 fork(建立子进程函数) 和 dup(克隆文件描述符)。
        1. flock 不能在 NFS 文件系统(网络文件系统,简单理解就是通过 mount 挂载的文件)上使用,如果要在 NFS 使用文件锁,请使用 fcntl。
        2. flock 锁可递归,即通过 dup 或者或者 fork 产生的两个 fd,都可以加锁而不会产生死锁。也就是说持有 flock 锁的进程还可以再次上锁而不会引起死锁。flock 创建的锁和文件描述符是关联的,这就意味着复制文件 fd(通过 fork 或者 dup)后,那么通过这两个 fd 都可以操作这把锁(例如通过一个 fd 加锁,通过另一个 fd 可以释放锁),也就是说子进程继承父进程的锁 。但是上锁过程中关闭其中一个 fd,锁并不会释放(因为 file 结构并没有释放),只有关闭所有复制出的 fd,锁才会释放。

示例 1:dup 对 flock 的影响

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/file.h>
int main(int argc, char ** argv)
{int ret;int fd1 = open("./1.txt",O_RDWR);int fd2 = dup(fd1);printf("fd1: %d, fd2: %d\n", fd1, fd2);ret = flock(fd1,LOCK_EX);printf("get lock1, ret: %d\n", ret);ret = flock(fd2,LOCK_EX);printf("get lock2, ret: %d\n", ret);return 0;
}

运行结果显示对 fd1 上锁并不会影响对 fd2 的上锁

示例 2:fork 对 flock 的影响

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/file.h>
int main(int argc, char ** argv)
{int ret;int fd = open("./tmp.txt",O_RDWR);int pid = fork();if (pid == 0){ret = flock(fd,LOCK_EX);printf("child get lock, fd: %d, ret: %d\n",fd, ret);sleep(10);printf("child exit\n");exit(0);}ret = flock(fd,LOCK_EX);printf("parent get lock, fd: %d, ret: %d\n", fd, ret);printf("parent exit\n");return 0;
}

运行结果显示子进程持有锁,并不影响父进程通过相同的 fd 获取锁,反之亦然。

示例 3:多次 open 获取文件描述符 fd,不继承 flock 锁

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/file.h>
int main (int argc, char ** argv)
{int ret;int fd1 = open("./1.txt",O_RDWR);int fd2 = open("./1.txt",O_RDWR);printf("fd1: %d, fd2: %d\n", fd1, fd2);ret = flock(fd1,LOCK_EX);printf("get lock1, ret: %d\n", ret);ret = flock(fd2,LOCK_EX | LOCK_NB);printf("get lock2, ret: %d\n", ret);return 0;
}

运行结果显示 fd1 获取锁后,fd2 无法获取

lockf 函数和 fcntl 函数

头文件:
#include <unistd.h>
函数原型:
int lockf(int fd, int cmd, off_t len);
函数描述:
        lockf()函数允许将文件区域用作信号量(监视锁),或用于控制对锁定进程的访问(强制模式记录锁定)。试图访问已锁定资源的其他进程将返回错误或进入休眠状态,直到资源解除锁定为止。当关闭文件时,将释放进程的所有锁定,即使进程仍然有打开的文件。当进程终止时,将释放进程保留的所有锁定。
参数描述:
        fd:文件描述符
        cmd:属性设置选项
                F_LOCK:给文件互斥加锁,若文件以被加锁,则会一直阻塞到锁被释放
                F_TLOCK:同 F_LOCK,不过是以非阻塞方式加锁
                F_ULOCK:解锁
                F_TEST 测试文件是否被上锁,若文件没被上锁则返回 0,否则返回-1。
        len:为从文件当前位置的起始要锁住的长度,如果为0表示整个文件
返回值:
        如果成功,则返回 0 。如果出现错误,则返回 -1 ,并适当地设置 errno
fcntl/lockf 的特性:
1. 上锁可递归,如果一个进程对一个文件区间已经有一把锁,后来进程又企图在同一区间再加一把锁,则新锁将替换老锁。
2. 加读锁(共享锁)文件必须是读打开的,加写锁(排他锁)文件必须是写打开。
3. 进程终止时,他所建立的所有文件锁都会被释放,对于 flock 也是一样的。
4. 任何时候关闭一个描述符时,则该进程通过这一描述符可以引用的文件上的任何一把锁都被释放(这些锁都是该进程设置的),这一点与 flock 不同。如:
fd1 = open (pathname, …);
lockf ( fd1 , F_LOCK , 0 );
fd2 = dup ( fd1 );
close ( fd2 );
则在 close(fd2) 后,再 fd1 上设置的锁也会被释放,如果将 dup 换为 open ,以打开另一描述符上的同一文件,则效果也一样。如下
fd1 = open (pathname, …);
lockf ( fd1 , F_LOCK , 0 );
fd2 = open (pathname, …);
close ( fd2 );
5. fork 产生的子进程不继承父进程所设置的锁,这点与 flock 也不同。
6. 在执行 exec 后,新程序可以继承原程序的锁,这点和 flock 是相同的。(如果对 fd 设置了 close-on-exec ,则 exec 前会关闭 fd ,相应文件的锁也会被释放)。
fcntl/lockf 的关系
那么 flock lockf/fcntl 所上的锁有什么关系呢?答案时互不影响。测试程序如下:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/file.h>
int main(int argc, char **argv)
{int fd, ret;int pid;fd = open("./1.txt", O_RDWR);ret = flock(fd, LOCK_EX);printf("flock return ret : %d\n", ret);ret = lockf(fd, F_LOCK, 0);printf("lockf return ret: %d\n", ret);sleep(10);return 0;
}

        可见 flock 的加锁,并不影响 lockf 的加锁。两外我们可以通过 /proc/locks 查看进程获取锁的状态。
我们可以看到 /proc/locks 下面有锁的信息:我现在分别叙述下含义:
POSIX FLOCK 这个比较明确,就是哪个类型的锁。 flock 系统调用产生的是 FLOCK
fcntl 调用 F_SETLK F_SETLKW 或者 lockf 产生的是 POSIX 类型,有次可见两种调用产生的
锁的类型是不同的;
ADVISORY 表明是劝告锁
WRITE 顾名思义,是写锁还是读锁;
2650 是持有锁的进程 ID 。当然对于 flock 这种类型的锁,会出现进程已经退出的状况。
00:37:906 表示的对应磁盘文件的所在设备的主设备号,次设备号,还有文件对应的 inode
number
0 表示的是所的起始位置
EOF 表示的是结束位置。 这两个字段对 fcntl 类型比较有用,对 flock 来是总是 0
EOF
备注:
        fcntl 不做详细介绍,具体用法可查看文件 IO 资料的 2.23 节

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/82960.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

知识付费平台开发技术实践:构建数字学习的未来

引言 知识付费平台的兴起正在塑造着数字学习的未来。本文将介绍一些关键的技术实践&#xff0c;帮助开发者构建强大的知识付费平台&#xff0c;提供出色的数字学习体验。 1. 选择适当的技术栈 在开始知识付费平台的开发之前&#xff0c;首要任务是选择适当的技术栈。这包括…

TS中的数据类型

一、number类型 let c: number; c 10; c "hello"; // 不能复制string类型 二、string类型 let d: string; d "hello"; d 10; // 不能复制number类型 三、boolean类型 let e: boolean true; e false; e 10; // 不能赋值true和false以外的值 四…

嵌入式裸机轻量级架构探索总结

为什么会想着探索下嵌入式裸机的架构呢&#xff1f;是因为最近写了一个项目&#xff0c;项目开发接近尾声时&#xff0c;发现了一些问题&#xff1a; 1、项目中&#xff0c;驱动层和应用层掺杂在一起&#xff0c;虽然大部分是应用层调用驱动层&#xff0c;但是也存在驱动层调用…

笔试面试相关记录(4)

&#xff08;1&#xff09;实现防火墙的主流技术有哪些&#xff1f; 实施防火墙主要采用哪些技术 - 服务器 - 亿速云 (yisu.com) &#xff08;2&#xff09; char arr[][2] {a, b, c, d}; printf("%d", *(arr1)); 输出的是谁的地址&#xff1f;字符c 测试代码如下…

ThreeJS-3D教学一基础场景创建

Three.js 是一个开源的 JS 3D 图形库&#xff0c;用于创建和展示高性能、交互式的 3D 图形场景。它建立在 WebGL 技术之上&#xff0c;并提供了丰富的功能和工具&#xff0c;使开发者可以轻松地构建令人惊叹的 3D 可视化效果。 Three.js 提供了一套完整的工具和 API&#xff0…

JUC中创建的组件 多线程使用“哈希表”

JUC中创建的组件 JUC中创建的组件这些内容都不太常用&#xff0c;偶尔用到面试的时候&#xff0c;偶尔用到&#xff01;到时候自行查找即可&#xff0c;本文主要来快速的过一下&#xff0c;留个印象即可~ JUC&#xff08;java.util.concurrent&#xff09;和多线程相关的工具…

python从入门到精通(一)

自己也有三四年的码龄了&#xff0c;目前&#xff0c;重拾起自己的博客&#xff0c;记录自己的学习笔记&#xff0c;为大家提供优质内容&#xff0c;也来巩固自己的学习内容。 很开心也成功成为了一名研究生&#xff0c;张张的研究方向是图像处理和计算机视觉这一块&#xff0c…

C++QT 作业8

#include "mywind.h" #include "ui_mywind.h" #include <iostream> #include <QIcon> #include <QLabel> #include <QLineEdit> #include <QDebug>//信息调试类 用于输出数据 Mywind::Mywind(QWidget *parent): QWidget(pa…

python3.11版本pip install ddddocr调用时报错got an unexpected keyword argument ‘det‘ 解决

一、如图出现如下问题 ddddocr.__init__() got an unexpected keyword argument det出现问题原因&#xff1a;python3.11默认安装版本就旧版的ddddocr1.0的&#xff0c;所以导致如下报错 二、解决方案一&#xff08;推荐&#xff09; python3.11的环境直接安装这个即可&…

物 理 层

二、物理层 1、物理层的基本概念 物理层的作用:尽可能的屏蔽掉传输媒体和通信手段的差异&#xff0c;使物理层上面的数据链路层感觉不到这些差异&#xff0c;使其只需要考虑如何完成本层的协议和服务 1.1、物理层的主要任务 机械特性&#xff1a;指明接口所用的接线器的形状…

关闭禁用chrome浏览器的阅读清单/强力书签

文章目录 前言操作 前言 阅读清单对我没啥用&#xff0c;还占用我位置&#xff0c;不小心点击到啥的&#xff0c;必须弃用 操作 chrome地址栏输入 chrome://flags/ 搜索book &#xff0c;关掉下面几个功能

Java 华为真题-猴子爬山

需求&#xff1a; 一天一只顽猴想去从山脚爬到山顶&#xff0c;途中经过一个有个N个台阶的阶梯&#xff0c;但是这猴子有一个习惯&#xff1a;每一次只能跳1步或跳3步&#xff0c;试问猴子通过这个阶梯有多少种不同的跳跃方式&#xff1f; 输入描述 输入只有一个整数N&#xff…

MySQL版数据库原理与应用期末复习重点(3)---画E-R图

文章目录 一、题目一1.1 题目描述1.2 解答 二、题目二2.1 题目描述2.2 解答 一、题目一 1.1 题目描述 设开发一个校园公共自行车管理系统&#xff0c;系统需要达到如下要求&#xff1a; &#xff08;1&#xff09;用户能够注册登录&#xff0c;能够根据借车点的名称查询借车…

若依注册的时候给个默认部门出现获取用户信息异常

想在注册的时候在数据库中查询一个部门给它一个默认部门&#xff0c;结果出现异常——【[handleServiceException,59] - 获取用户信息异常】 经分析代码&#xff0c;此方法有如下注解 以上注解会在mapper.xml中做如下操作 在做此操作之前会进入一个拦截器&#xff0c;根据token…

PHP-composer安装扩展安装,批量操作合并pdf

清除Composer缓存&#xff1a; 运行以下命令来清除Composer的缓存&#xff0c;并再次尝试安装包。 bash composer clear-cache 使用不同的镜像源&#xff1a; Composer使用的默认包源可能会受到限制或访问问题。你可以切换到使用其他镜像源&#xff0c;如阿里云、Composer中国…

安理【2022】

关键字&#xff1a; 出栈序列s2固定、快速排序2趟、next数组、二分查找比较次数log2n向上取整、 一、选择 二、填空 三、应用

Zookeeper 启动失败【Cannot open channel to 3 at election address...】

文章目录 完整报错信息解决方法1.检查文件夹权限2.未监听所有IP3.IP映射名称与 ID 不对应 完整报错信息 Cannot open channel to 3 at election address hadoop121/192.168.10.121:3888 java.net.ConnectException 解决方法 1.检查文件夹权限 检查当前用户是否拥有 Zookeep…

《Kubernetes部署篇:Ubuntu20.04基于containerd部署kubernetes1.25.14集群(多主多从)》

一、架构图 如下图所示: 二、环境信息 1、资源下载基于containerd部署容器版kubernetes1.25.14集群资源合集 2、部署规划主机名K8S版本系统版本内核版本IP地址备注k8s-master-121.25.14Ubuntu 20.04.5 LTS5.15.0-69-generic192.168.1.12master节点 + etcd节点k8s-master-131.…

adb shell命令查看当前屏幕可见最顶层Activity和Fragment及其调用栈

adb shell命令查看当前屏幕可见最顶层Activity和Fragment及其调用栈 &#xff08;1&#xff09;当前屏幕可见页面最顶层是哪个Activity: adb shell "dumpsys activity top | grep ACTIVITY | tail -n 1"&#xff08;2&#xff09;当前屏幕可见页面最顶层是哪个Fragm…

(图论) 827. 最大人工岛 ——【Leetcode每日一题】

❓ 827. 最大人工岛 难度&#xff1a;困难 给你一个大小为 n x n 二进制矩阵 grid 。最多 只能将一格 0 变成 1 。 返回执行此操作后&#xff0c;grid 中最大的岛屿面积是多少&#xff1f; 岛屿 由一组上、下、左、右四个方向相连的 1 形成。 示例 1: 输入: grid [[1, 0]…