linux 文件锁

news2024/11/24 3:04:14

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

建议锁:
        如果某一个进程对一个文件持有一把锁之后,其他进程仍然可以直接对文件进行操作(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.coloradmin.cn/o/1024588.html

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

相关文章

@JsonFormat、@JSONField、@DateTimeFormat详细解说

JsonFormat、JSONField、DateTimeFormat详细解说_jsonfield format_xinlianluohan的博客-CSDN博客 三者出处 1、JsonFormat来源于jackson&#xff0c;Jackson是一个简单基于Java应用库&#xff0c;Jackson可以轻松的将Java对象转换成json对象和xml文档&#xff0c;同样也可以…

CSS SASS calc() 计算表达式或使用变量

calc&#xff08;&#xff09;是css的一个函数&#xff0c;可用于元素计算长度&#xff0c;比如div宽度想要减去一个固定宽度后并自适应&#xff0c;可以写为calc(100% - 60px) 注意“-”两边有空格 sass已经是常用的预编译语言&#xff0c;允许使用变量等规则&#xff0c;如果…

上海亚商投顾:沪指窄幅震荡微跌 两市成交金额创年内新低

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指昨日窄幅震荡&#xff0c;创业板指盘中跌超1%&#xff0c;黄白二线有所分化。华为星闪概念股午后拉升&…

EPC与5GC/5GS互联互通

一、5GS与EPC/E-UTRAN互通的非漫游架构 1&#xff0e;N26接口是MME和5GS AMF之间的CN间接口&#xff0c;以实现EPC和NG核心之间的互通。网络中支持N26接口是可选的&#xff0c;用于互通。N26支持在S10上支持的功能的子集&#xff08;对于互通是必要的&#xff09;。 2&#xf…

面试题:HTTPS 是如何保证传输安全的?又被问了!

文章目录 1. HTTP 协议1.1 HTTP 协议介绍1.2 HTTP 中间人攻击1.3 防止中间人攻击 2. HTTPS 协议2.1 HTTPS 简介2.2 CA 认证体系 总结 1. HTTP 协议 在谈论 HTTPS 协议之前&#xff0c;先来回顾一下 HTTP 协议的概念。 1.1 HTTP 协议介绍 HTTP 协议是一种基于文本的传输协议&…

Android13 大屏设备底部显示TaskBar并NavagatonBar居右

Android 13大屏设备时底下显示任务栏以及虚拟按键靠右的问题&#xff0c; 当前需求是去掉底部任务栏的显示&#xff0c;并把虚拟按键导航栏居中显示。 修改前的效果&#xff1a; 修改后的效果&#xff1a; 通过查看源码逻辑&#xff0c;可以发现只需把isTablet相关的逻辑和…

Mybatis 映射器中映射方法接受多个参数(@Param)

前面我们介绍了使用Mybatis映射器进行数据的增删改查操作&#xff1b;本篇我们继续介绍在Mybatis映射器的映射方法中如何使用多个参数。 如果您对Mybatis使用映射器进行数据的增删改查操作不太了解&#xff0c;建议您先进行了解后再阅读本篇&#xff0c;可以参考&#xff1a; …

【数据结构】二叉树的构建与基本操作实现

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.前序建立二叉树 2.销毁二叉树 3.统计 …

uni-app 之 picker选择器

uni-app 之 picker选择器 同步滚动&#xff1a;开 uni-app 之 picker选择器 一、普通选择器 二、多列选择器 三、时间选择器 四、日期选择器 一、普通选择器 <template><view><picker change"bindPickerChange" :value"index" :range&q…

LabVIEW开发航天器模拟器的姿态控制和反作用轮动量管理

LabVIEW开发航天器模拟器的姿态控制和反作用轮动量管理 在过去十年中&#xff0c;航天器一直是现代技术进步的先决条件。迄今为止&#xff0c;为了更好地完成各种实际任务&#xff0c;已经在航天器姿态控制领域进行了大量研究。航天器一旦进入太空&#xff0c;就容易出现不确定…

JavaWeb开发-05-SpringBootWeb请求响应

一.请求 1.Postman 2.简单参数 ​ package com.wjh.controller;import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;/** 测试请求参数接受*/ R…

【IntelliJ IDEA】cmd和idea Terminal查看java版本不一致

问题描述 原来win10电脑上安装的是jdk8的版本&#xff0c;因某些原因&#xff0c;现在想换成jdk7的版本&#xff0c;修改环境变量后&#xff0c;在cmd中执行 [java -version]命令&#xff0c;显示的是7的版本。 但在idea的Terminal中执行&#xff0c;确实显示8的版本。 原因分…

vue设置路由模式为history,打包部署,并解决404问题

现在Router配置里面加上 base 和 mode 属性&#xff1a; export default new Router({base: /your_project_name/,mode: history,routes: [......] })这样就能支持 history 模式了&#xff0c;但是现在静态资源获取还有问题。 解决静态资源获取问题 在 config/index.js 文件…

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以外的值 四…

Cypress安装与使用教程(1)—— 软测大玩家

&#x1f60f;作者简介&#xff1a;博主是一位测试管理者&#xff0c;同时也是一名对外企业兼职讲师。 &#x1f4e1;主页地址&#xff1a;【Austin_zhai】 &#x1f646;目的与景愿&#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能&#xff0c;分享行业相关最新信息。…

半导体划片机工艺应用

半导体划片工艺是半导体制造过程中的重要步骤之一&#xff0c;主要用于将大尺寸的晶圆切割成小片&#xff0c;以便进行后续的制造和封装过程。以下是一些半导体划片工艺的应用&#xff1a; 晶圆划片&#xff1a;在半导体制造过程中&#xff0c;需要将大尺寸的晶圆切割成小片&am…

【数据库系统概论】数据库系统外部的体系结构

单用户结构主从式结构分布式结构客户机&#xff0f;服务器结构&#xff08;C/S结构&#xff09;浏览器 / 服务器结构&#xff08;B/S结构&#xff09;感谢 &#x1f496; 上一篇文章 数据库系统的三级模式和二级映射介绍的是数据库系统内部的体系结构&#xff0c;是从应用开发…

计算机网络知识补充(1)

计算机网络:是一个将分散的&#xff0c;具有独立功能的计算机系统&#xff0c;通过通信设备和线路进行连接起来&#xff0c;由功能完善的软件实现资源共享和信息共享的系统&#xff0c;计算机网络是互连的&#xff0c;自治的计算机集合 互连:通过通信链路来进行互联互通 自治:没…

云安全威胁和责任

云计算的共享特性和按需定制本质除了给企业带来效率上提升&#xff0c;也引入了新的安全威胁&#xff0c;有可能使企业得不偿失。 之前云安全联盟(CSA)的报告便指出&#xff0c;云服务天生就能使用户绕过公司范围内的安全策略&#xff0c;建立起自己的影子IT项目服务账户。 新的…

全面感知,智能预警!燃气感知云,守护城市“烟火气”

燃气安全如何保障&#xff1f;燃气企业如何精准运营&#xff1f;天翼物联基于感知云平台创新能力&#xff0c;提供燃气感知云服务&#xff0c;包括泛协议接入、感知云燃气平台、燃气感知数据治理、决策处置大屏四大服务&#xff0c;构建燃气行业感知神经系统新型数字化底座&…