Linux 文件锁 - fcntl
什么是文件锁?
即锁住文件,不让其他程序对文件做修改!
为什么要锁住文件?
案例,有两个程序,都对一个文件做写入操作。
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>#define FILE_NAME "flock_demo.txt"int main(void) {int fd = -1;char buf[64] = "hello, data one!\n"; // 程序1写入文件内容//char buf[64] = "hi, data two!\n"; // 程序2写入文件内容fd = open(FILE_NAME, O_RDWR|O_CREAT, 00666);if (fd < 0) {fprintf(stderr, "open file %s failed! reason: %s\n", FILE_NAME, strerror(errno));exit(-1);}int ret = write(fd, buf, sizeof(buf));if (-1 == ret) {fprintf(stderr, "write failed. reason: %s\n", strerror(errno));exit(-2);}printf("write successful! start sleep 10s...\n");sleep(10);close(fd);return 0;
}
程序1对文件flock_demo.txt写入hello, data one!
程序2对文件flock_demo.txt写入hi, data two!
然后都睡眠10秒后才调用close函数关闭文件,然后程序结束;
首先运行程序1,然后运行程序2,来看看运行后的文件结果!
根据图片测试结果可知,程序1先将hello, data one!写入文件,然后睡眠10秒钟;然后程序2将hi, data two!写入文件,将程序1写入的内容给覆盖掉了,然后睡眠10秒;10秒后程序1执行close函数关闭文件退出程序,10秒后程序2执行close函数关闭文件退出程序。
但此时文件内容保存的是程序2写入的内容,程序1的调用者肯定就会很纳闷了,为什么我调用程序应该要写入hello, data one!才对,它为什么写入了hi, data two!呢?
如果此时程序1执行一次,而程序二不执行,那么程序1就可以正常将hello, data one!写入到文件中去,那么程序1的调用就很懵逼了,百思不得其解。。。
基于以上情况,我们操作文件前需要使用文件锁!
#include <unistd.h>
#include <fcntl.h>
int fcntl (int fd, int cmd, ... /* arg */ );
描述:文件上锁、解锁等。
fd:
文件描述符;
cmd:
取值 F_GETLK, F_SETLK 和 F_SETLKW,分别表示获取锁、设置锁和同步设置锁.
返回值:
成功: 返回 0;或者返回:F_DUPFD、F_GETFD、F_GETFL、F_GETLEASE、F_GETOWN、F_GETSIG、F_GETPIPE_SZ;对于一个成功的调用,返回值取决于操作;
失败: 返回 -1,并且设置错误编号 errno ,可用( strerror(errno) ) 查看.
文件锁的表示
struct flock {short l_type; /* Type of lock: F_RDLCK, F_WRLCK, F_UNLCK */short l_whence; /* How to interpret l_start: SEEK_SET, SEEK_CUR, SEEK_END */off_t l_start; /* Starting offset for lock */off_t l_len; /* Number of bytes to lock */pid_t l_pid; /* PID of process blocking our lock(F_GETLK only) */
};
l_type 有三种状态:
F_RDLCK 设置读锁
F_WRLCK 设置写锁
F_UNLCK 设置解锁
l_whence 也有三种方式:
SEEK_SET 以文件开头为锁定的起始位置。
SEEK_CUR 以目前文件读写位置为锁定的起始位置
SEEK_END 以文件结尾为锁定的起始位置。
// struct flock 结构体说明 struct flock { short l_type; /*F_RDLCK, F_WRLCK, or F_UNLCK */ off_t l_start; /*offset in bytes, relative to l_whence */ short l_whence; /*SEEK_SET, SEEK_CUR, or SEEK_END */ off_t l_len; /*length, in bytes; 0 means lock to EOF */ pid_t l_pid; /*returned with F_GETLK */ }; l_type: 第一个成员是加锁的类型:只读锁,读写锁,或是解锁。 l_start和l_whence: 用来指明加锁部分的开始位置。 l_len: 是加锁的长度。设0表示对整个文件加锁。 l_pid: 是加锁进程的进程id。 举例: 我们现在需要把一个文件的前三个字节加读锁,则该结构体的l_type=F_RDLCK, l_start=0, l_whence=SEEK_SET, l_len=3, l_pid=-1,然后调用fcntl函数时, cmd参数设F_SETLK. |
1. 文件上锁
struct flock fflock;
memset(&fflock, 0, sizeof(struct flock));// 上锁
fflock.l_type = F_WRLCK; /* 写锁 */
//fflock.l_type = F_RDLCK; /* 读锁 */fflock.l_whence = SEEK_SET;
fflock.l_start = 0;
fflock.l_len = 0; // 为0,锁整个文件
fflock.l_pid = -1;// 上锁或解锁,判断是否成功
//if (fcntl(fd, F_SETLKW, &fflock) < 0) {
if (fcntl(fd, F_SETLK, &fflock) < 0) {fprintf(stderr, "set file lock failed! reason: %s\n", strerror(errno));return -1;
}
2. 文件解锁
struct flock fflock;
memset(&fflock, 0, sizeof(struct flock));fflock.l_type = F_UNLCK; // 解锁
fflock.l_whence = SEEK_SET;
fflock.l_start = 0;
fflock.l_len = 0; // 为0,解锁整个文件
fflock.l_pid = -1;// 上锁或解锁,判断是否成功
//if (fcntl(fd, F_SETLKW, &fflock) < 0) {
if (fcntl(fd, F_SETLK, &fflock) < 0) {fprintf(stderr, "set file lock failed! reason: %s\n", strerror(errno));return -1;
}
3. 获取文件是否上锁
struct flock fflock;
memset(&fflock, 0, sizeof(struct flock));// 获取当前文件是否已经上锁
int ret = fcntl(fd, F_GETLK, &fflock); // F_GETLK
if (-1 == ret) {fprintf(stderr, "fcntl get lock failed! reason: %s\n", strerror(errno));return -1;
}// 文件已上锁
if (fflock.l_type != F_UNLCK) {if (fflock.l_type == F_RDLCK) { // 文件已上读锁printf("flock has been set to read lock by %d\n", fflock.l_pid);// return; } else if (fflock.l_type == F_WRLCK) { // 文件已上写锁printf("flock has been set to write lock by %d\n", fflock.l_pid);// return;}return -1;
}
例:
#include <unistd.h>
#include <fcntl.h> // file lock
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>#define FILE_NAME "flock_demo.txt"int flock_set(int fd, int type) {// 获取当前进程idprintf("pid = %d come in.\n", getpid());struct flock fflock;memset(&fflock, 0, sizeof(struct flock));// 获取当前文件是否已经上锁int ret = fcntl(fd, F_GETLK, &fflock);if (-1 == ret) {fprintf(stderr, "fcntl get lock failed! reason: %s\n", strerror(errno));return -1;}// 文件已上锁if (fflock.l_type != F_UNLCK) {if (fflock.l_type == F_RDLCK) {printf("flock has been set to read lock by %d\n", fflock.l_pid);} else if (fflock.l_type == F_WRLCK) {printf("flock has been set to write lock by %d\n", fflock.l_pid);}return -1;}// lock filefflock.l_type = type;fflock.l_whence = SEEK_SET;fflock.l_start = 0;fflock.l_len = 0;fflock.l_pid = -1;// 上锁或解锁,判断是否成功//if (fcntl(fd, F_SETLKW, &fflock) < 0) {if (fcntl(fd, F_SETLK, &fflock) < 0) {fprintf(stderr, "set file lock failed! reason: %s\n", strerror(errno));return -1;}switch(fflock.l_type) {case F_RDLCK: {printf("read lock is set by %d\n", getpid());}break;case F_WRLCK: {printf("write lock is set by %d\n", getpid());}break;case F_UNLCK: {printf("lock is released by %d\n", getpid());}break;default:break;}printf("Process pid = %d out.\n", getpid());return 0;
}int main(void) {int fd = -1;fd = open(FILE_NAME, O_RDWR|O_CREAT, 00666);if (fd < 0) {fprintf(stderr, "open file %s failed! reason: %s\n", FILE_NAME, strerror(errno));exit(-1);}// 1.F_WRLCKint ret = flock_set(fd, F_WRLCK); // 写锁//int ret = flock_set(fd, F_WRLCK); // 读锁if (-1 != ret) {getchar();// 2.F_UNLCKflock_set(fd, F_UNLCK);getchar();}close(fd);return 0;
}
用以上的代码编译一个读锁程序,编译一个写锁程序:
main函数中替换以下代码进行编译
int ret = flock_set(fd, F_WRLCK); // 写锁
int ret = flock_set(fd, F_WRLCK); // 读锁
gcc file_lock.c -o file_w_lock
gcc file_lock.c -o file_r_lock
1. 设置锁使用:F_SETLK
情况一:读锁 和 读锁
结论:可以看出,两个程序都可以对文件进行加读锁!
情况二:读锁 和 写锁
结论:当文件上读锁后,就无法再给文件上写锁,且也无法检测处文件上锁状态;
即(./file_w_lock)执行代码 int ret = fcntl(fd, F_GETLK, &fflock); 后,其 fflock.l_type != F_UNLCK ,所以没法做中断操作;下面再对文件进行上锁操作,就函数返回-1了!
情况三:写锁 和 读锁
结论:文件上写锁后,再给文件上读锁,可以被检测出来文件已经上锁了,程序就返回结束了
情况四:写锁 和 写锁
结论:文件上写锁后,再给文件上写锁,可以被检测出来文件已经上锁了,程序就返回结束了
2. 设置锁使用:F_SETLKW
使用F_SETLKW会有等待阻塞的情况!
情况一:读锁 和 读锁
结论:可以看出,两个程序都可以对文件进行加读锁!
情况二:读锁 和 写锁
先给文件上读锁,再个文件上写锁,此时上写锁程序在获取文件的上锁状态时,被阻塞在此等待;
当我们在程序1那里按下回车键后,对文件解锁;右边程序就可以正常对文件上写锁了;否则会一直阻塞。。。
情况三:写锁 和 读锁
文件上写锁后,再给文件上读锁,可以被检测出来文件已经上写锁了,程序就返回结束了
情况四:写锁 和 写锁
结论:文件上写锁后,再给文件上写锁,可以被检测出来文件已经上写锁了,程序就返回结束了
3. 其他情况
这里还有另一种情况,就是程序1对文件上锁,程序2没有对文件上锁,然后对文件做写入操作
程序1还是上面的程序代码;
程序2代码如下:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>#define FILE_NAME "flock_demo.txt"int main(void) {int fd = -1;char buf[64] = "write file data...\n";fd = open(FILE_NAME, O_RDWR|O_CREAT, 00666);if (fd < 0) {fprintf(stderr, "open file %s failed! reason: %s\n", FILE_NAME, strerror(errno));exit(-1);}int ret = write(fd, buf, sizeof(buf));if (-1 == ret) {fprintf(stderr, "write failed. reason: %s\n", strerror(errno));exit(-2);}printf("write successful!\n");close(fd);return 0;
}
gcc file_write.c -o file_write
文件上读锁:
程序1给文件上读锁后,程序2依然可以 对文件做写入操作!
文件上写锁:
程序1给文件上写锁后,程序2依然可以对文件做写入操作!
结论:
由以上两个测试可知,给文件上锁,仅仅对相应也给文件上锁的程序可以限制,对于没有对文件上锁的程序无任何限制!
所以,在开发中,就得做出规定,大家对文件操作时都得对文件上锁后再进行操作!
总结
文件上锁的几种情况已经列举出来了,使用时注意一下就行!
相关文章:
Linux 文件锁 - fcntl
什么是文件锁? 即锁住文件,不让其他程序对文件做修改! 为什么要锁住文件? 案例,有两个程序,都对一个文件做写入操作。 #include <unistd.h> #include <stdio.h> #include <stdlib.h> …...
CellularAutomata元胞向量机-2-初等元胞自动机MATLAB代码分享
%% 二维元胞自动机%imagesc(a)的色度矩阵a中0->256由蓝变黄% 规则,先把中间点置为1,每一时间每一点如果%周围八个点和为偶数,则变为0,为奇数则变为 1% 颜色控制clc, clearMap [1 1 1; 0 0 0];% [0 0 0] is black, [1 1 1] is …...
OpenStack云平台搭建(6) | 部署Neutron
目录 1.在控制节点登录数据库配置 2.要创建服务证书,完成这些步骤 3.创建网络服务API端点: 4.安装网络组件 5.配置neutron组件 6.配置 Modular Layer 2 (ML2) 插件 7.配置Linuxbridge代理 8.配置DHCP代理 9.配置元数据代理 10.编辑/etc/nova/no…...
Lesson 05.Configuring the Oracle Network Environment
Lesson 05. Configuring the Oracle Network Environment 文章目录Lesson 05. Configuring the Oracle Network Environment1. 监听程序的配置文件有哪些,如何命名,保存在什么位置?2. Oracle 网络的服务名称文件是如何命名的,需要…...
理论五:接口vs抽象类的区别,如何用普通的类模拟抽象类和接口
在面向对象编程中,抽象类和接口是两个经常被用到的语法概念,是面向对象四大特性,以及很多设计模式、设计思想、设计原则编程实现的基础。比如,我们可以使用接口来实现面向对象的抽象特性、多态特性和基于接口而非实现的设计原则,使用抽象类来实现面向对象的继承特性和模板设计模…...
【Hello Linux】 Linux的权限以及Shell原理
作者:小萌新 专栏:Linux 作者简介:大二学生 希望能和大家一起进步! 本篇博客简介:介绍Linux的基础命令 Linux的权限以及Shell原理Shell的运行原理权限Linux中权限的概念如何切换用户如何提升当前操作的权限如何添加信任…...
【STM32】【HAL库】遥控关灯2 分机
相关连接 【STM32】【HAL库】遥控关灯0 概述 【STM32】【HAL库】遥控关灯1主机 【STM32】【HAL库】遥控关灯2 分机 【STM32】【HAL库】遥控关灯3 遥控器 需求 接收RF433和红外信号,根据信号内容控制舵机 硬件设计 主控采用stm32F103c6 STM32 433接收 其他接口 软件设计 接…...
代码随想录算法训练营第27天|● 93.复原IP地址 ● 78.子集 ● 90.子集II
93.复原IP地址 看完题后的思路 典型分割问题略lue略剪枝条件 sub: 1) 不是一位首字母为0 2)大于三位 3)介于0-255之间 4) 当已分割得到3个时,第四个直接从startIndex到末尾就行 代码 ArrayList<String> slist…...
Unity UI合批的问题
今天看到一个问题,主要说的是Unity中的UI资源合批的问题之前一直以为主要和UI资源在Hierarchy中的排列顺序有关,但其实这并不是最主要的,因为Unity会对同一个Canvas下的UI进行排序(注:不同Canvas下的资源是不能够合批的…...
MWORKS--系统建模与仿真
MWORKS--系统建模与仿真1 系统定义特征2 系统研究2.1 特点与原则2.2 方法百度百科归纳同元杠归纳3 系统建模与仿真3.1 系统、模型、仿真的关系3.2 系统建模4 建模方法4.1 方法4.2 一般流程4.3 目的5 仿真方法5.1 方法5.2 流程参考1 系统定义 系统是由相互作用相互依赖的若干组…...
PC端开发GUI
PC端开发GUI 一、搭建PC端环境:常规方式1、Python2、Pycharm二、搭建PC端环境:创建虚拟环境1、创建文件夹存放虚拟环境相关2、配置环境变量3、创建.ui文件4、.ui文件转成.py文件5、打包.py文件来发布.exe一、搭建PC端环境:常规方式 1、Python 注意Python版本不能超过3.9,…...
解读手机拍照的各个参数(拍照时,上面会有6个符号)
1第一个符号是闪光灯符号,如下图所示。有四种模式, 手机的闪光灯分别为关闭、自动、开启和常亮四种状态。 关闭:就是在任何情况下都不会闪光 自动:由手机来判断此时的光线强弱,若手机测光认为光线太弱,则…...
数字钥匙最新进展文章
在未来出行上,智能汽车越来越卷。 新车除了拼高精度激光雷达、堆大算力芯片、标配辅助驾驶、智能语音识别,还在车钥匙上展开了激烈角逐,越来越多的厂商开始在量产车型上搭载数字钥匙,实现无钥匙进入车内。 去年1月蔚来发布轿车E…...
如何在VMware虚拟机上安装运行Mac OS系统(详细图文教程)
一、安装前准备 虚拟机运行软件:VMware Workstation Pro,版本:16.0.0 。VMware Mac OS支持套件:Unlocker。Mac OS系统镜像。 如果VMware 在没有安装Unlocker的情况下启动,在选择客户机操作系统时没有支持Mac OS的选项…...
C++中的强制类型转换
接触过C语言的朋友都知道,C语言中也有强制类型转换,但是C语言中的强制类型转换会有一些问题,比如: int a 0x1234; char b (char)a; 上述的代码出现一个问题就是a 这个int型强制转化成b 这个char型时损失了一些精度,…...
任何人都可以学习Rasa之优秀Rasa学习资源推荐
任何人都可以学习Rasa之优秀Rasa学习资源推荐 欢迎同学们报名Gavin老师的Rasa系列课程,任何人都可以学习Rasa之优秀Rasa学习资源推荐: 1.NLP on Transformers高手之路137课 2 .Rasa 3.X 智能对话机器人案例开发硬核实战高手之路 (7大项目Ex…...
数据中心的 TCP-Delay ACK 与 RTO, RACK
TCP 对 RTO 有个最小值限制,一般限制为 MIN_RTO 200ms。之所以有这个限制,在于要适应 Delay ACK,而 Delay ACK 的意义,不多说,摘自 RFC1122: MIN_RTO 应该足够大,以覆盖 Delay ACK 的影响&…...
MySQL与常见面试题
目录 事务概述ACIDAUTOCOMMIT总结并发一致性问题丢失修改读脏数据不可重复读幻读原因和解决方法隔离级别未提交读(READ UNCOMMITTED)提交读(READ COMMITTED)可重复读(REPEATABLE READ)可串行化(SERIALIZABLE)加锁封锁粒度封锁类型读写锁意向锁...
FFmpeg进阶: 采用音频滤镜对音频进行转码
文章目录采样位数采样率声道布局码率使用FFmpeg音频滤镜进行转码参考链接很多时候为了让视频文件适应不同的播放领域,我们需要对音频文件进行转码操作,转码操作其实主要就是修改音频文件的各种参数包括:采样位数、采样率、音频布局、码率等等。下面分别介…...
C++:AVL树
AVL树的概念 二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下,时间复杂度为O(N); 两位俄罗斯的数学家G.M.Ade…...
Docker中安装Oracle-12c
前言 MySQL和Oracle是开发中常用到的两个关系型数据库管理系统,接上一期内容,这一期在Docker中完成oracle-12c的安装和配置。 安装oracle-12c 1、拉取oracle-12c镜像 启动Docker Desktop后在cmd窗口中执行docker search oracle命令,搜索O…...
教你如何用Python分析出选注双色球号码
前言 嗨喽,大家好呀~这里是爱看美女的茜茜呐 又到了学Python时刻~ 数据集介绍 找从19年到现在的开奖历史数据,我们首先要把这个历史数据拿到, 拿到我们再进行做分析,分析每个号码出现的频率是多少, 哪个多&#x…...
elasticsearch映射及字段类型
查询映射关系类型上对字段的类型进行映射,我们前面知道可以通过get方法请求_mapping查询指定类型的映射关系:此语句可以查询get-together索引下的group类型的映射关系更新映射关系使用put方法可以更新类型的映射这里指定了new-events类型的字段映射关系&…...
1493围圈报数(队列)
题目描述 有n个人依次围成一圈,从第1个人开始报数,数到第m个人出列,然后从出列的下一个人开始报数,数到第m个人又出列,…,如此反复到所有的人全部出列为止。…...
【ArcGIS Pro二次开发】(2):创建一个Add-in项目
Add-In即模块加载项,是一种能够快速扩展桌面应用程序功能的全新扩展方式。 一、创建新项目 1、打开VS2002,选择创建新项目。 2、在搜索框中输入“arcgis pro”,在搜索结果中选择【ArcGIS Pro 模块加载项】创建项目,注意选择语言应…...
浏览器缓存是如何提升网站访问速度的
提升速度,降低负载 浏览器访问一个页面时,会请求加载HTML、CSS和JS等静态资源,并把这些内容渲染到屏幕上。 对浏览器来说,如果页面没有更新,每次都去请求服务器是没有必要的。所以,把下载的资源缓存起来&…...
Linux中几个在终端中有趣的命令
uhh…最近我不知道该更新些什么,所以就更新Linux几个很有趣的命令 文章目录前言1.命令:sl安装 sl输出2. 命令:telnet命令:fortune安装fortune4.命令:rev(反转)安装rev5. 命令:factor…...
快来来试试SpringBoot3 中的新玩意~
你还在用OpenFeign嘛?快来试试 SpringBoot3 中的这个新玩意!声明式HTTP调用 1、由来 Spring Boot3 去年底就已经正式发布,我也尝了一把鲜,最近有空会和小伙伴们慢慢聊聊 Spring Boot3 都给我们带来了哪些新东西。 今天我们就先…...
【寻人启事】达坦科技持续招人ing
❤️一起来探索前沿科技,做有意思的事情~ 我们是谁 达坦科技(DatenLord)专注于打造新一代开源跨云存储平台。通过软硬件深度融合的方式打通云云壁垒,实现无限制跨云存储、跨云联通,建立海量异地、异构…...
【C/C++基础练习题】简单函数练习题
🍉内容专栏:【C/C要打好基础啊】 🍉本文内容:简单函数使用练习题(复习之前写过的实验报告) 🍉本文作者:Melon西西 🍉发布时间 :2023.2.11 目录 1.给定某个年…...
长沙营销企业网站建设/北京建站
什么是软膜灯箱?软膜灯箱属于超薄灯箱的一种,我们把他分为这几类:光面软膜灯箱,缎光面软膜灯箱,透光面软膜灯箱,基本膜软膜灯箱,绒面软膜灯箱,金属面软膜灯箱和冲孔面软膜灯箱。随着灯箱技术这…...
网站邮件设置/信息流优化师工作内容
问题背景 聚合支付系统(第四方支付),协议支付模块一直有个小问题。 商户调用协议支付接口,该模块会调用下层第三方支付渠道的协议支付服务,如果第三方支付渠道没有同步返回支付结果,则协议支付模块会通过定…...
个人电子商务网站建设/即时热榜
代码补全失效,编译器选项重设一下补全延迟。看清楚用if还是else if,比如if(a<b){ab} else if(ab){} 不用else意思完全不一样。for里套while注意for里i的自增。运行超时该clang;typedef long long ll;函数要改变实参加引用。排序题id直接写成string类型…...
网页传奇游戏 垃圾/南京seo外包
一、UART UART是一个大家族,其包括了RS232、RS499、RS423、RS422和RS485等接口标准规范和总线标准规范。它们的主要区别在于其各自的电平范围不相同。 嵌入式设备中常常使用到的是TTL、TTL转RS232的这种方式。常用的就三根引线:发送线TX、接收线RX、电平…...
网站备案期间可以做推广吗/洛阳网站建设
推荐书目详细介绍,请参阅文件:充电书库-Q4第一期推荐书目.xlsx 序号 书名 作者 序号 书名 作者 1原则[美] 瑞达利欧;2当下的力量埃克哈特•托利 (Eckhart Tolle);3创业维艰:如何完成比难更难的事本霍洛维茨4心理学…...
wordpress linux/苏州seo关键词优化推广
出于某种原因,需要把百度地图中的聚合方法在java中实现,自己写了一份。 当时做的功能是把聚合后的点存入数据库中,并且需要计算的数值比较多,因此显得麻烦些,我已经把代码进行了一些删减。(本来是想提供一…...