linux file lock文件锁
2022-11-21 16:46 youxin 阅读(1098) 评论(0) 编辑 收藏 举报http://www.kaotop.com/it/37363.html
https://www.codenong.com/cs106758831/
上锁
文件锁有两种
shared lock 共享锁
exclusive lock 排他锁
当文件被上了共享锁之后,其他进程可以继续为此文件加共享锁,但此文件不能被加排他锁,此文件会有一个共享锁计数,加上一个共享锁计数+1,解锁后-1,只有当共享锁计数为0时,才有可能被上排他锁。
当文件被上了排锁之后,在解锁前,不能上共享锁和排他锁。
命令flock [options] [command args]
flock [options] -c
flock [options]
options:-s, -share 读锁,共享锁
-x, -e, --exclusive 写锁,独占锁,这是默认值
-u, --unlock 解锁,通常不需要解锁,因为在文件关闭时会自动解锁
-n, --nonblock 无法立刻获取锁定时退出,而不是等待
-w, --timeout 几秒内无法获取锁定则退出
-E, --conflict-exit-code exit code after conflict or timeout
-o, --close close file descriptor before running command
-c, --command 提供一个字符串形式的shell命令来执行
-h, --help display this help and exit
-V, --version output version information and exit
示例[root@localhost ~]# flock -s ~/test.lock -c "sleep 10" &
# 在flock.lock文件上加排他锁后,执行休眠30s flock -x flock.lock -c 'sleep 30' # command 1
# 另起一个终端 flock -s flock.lock -c 'echo hello' # 会在 # <command 1> 执行后30s 输出'hello'
#加读锁
[1] 1854
[root@localhost ~]# flock -xn~/test.lock -c "echo 1"
Linux中的例行性工作排程crontab会定时执行一些脚本,但脚本的执行时间往往无法控制,当脚本执行时间过长时,可能会导致上一次任务的脚本还没执行完,下一次任务的脚本又开始执行了。
这种情况下可能会出现一些并发问题,严重时会导致出现脏数据/性能瓶颈的恶性循环。
-
使用flock命令
(1)使用方式如下,这个命令的好处是等待动作在flock命令中完成,无需另外添加代码。
( flock 300 …cmd… flock -u 300 ) > /tmp/file.lock
(2)但flock有个缺陷是,在打开flock之后fork(),子进程也会拥有锁,如果在flock其间有运行daemon的话,必需确保daemon在启动时已经关闭了所有的文件句柄,不然该文件会因为daemon一直将其置于打开状态而无法解锁。
2.使用flock命令
- flock 是对于整个文件的建议性锁。
(1)也就是说,如果一个进程在一个文件(inode)上放了锁,那么其它进程是可以知道的。(建议性锁不强求进程遵守。)
(2)最棒的一点是,它的第一个参数是文件描述符,在此文件描述符关闭时,锁会自动释放。
(3)而当进程终止时,所有的文件描述符均会被关闭。 - shell中实现flock系统调用的命令是flock,其格式为:
#cat /scripts/shell/file_lock.sh
#!/bin/bash
# Description: test for file flock
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo ""
echo "----------------------------------"
echo "start at `date '+%Y-%m-%d %H:%M:%S'` ..."
sleep 140s
echo "finished at `date '+%Y-%m-%d %H:%M:%S'` ..."
=====================创建定时任务:测试排它锁=========================================#crontab -e
* * * * * flock -xn /dev/shm/test.lock -c "sh /scripts/shell/file_lock.sh > /root/stdout.log"
##每分钟执行一次该脚本,并将输出信息写入到stdout.log
// write_1.cc #include <sys/file.h> #include <stdio.h> #include <assert.h> #include <string.h> int main(int argc,char* argv[]){ const char* lock_file_path = "flock.lock"; if(argc >= 2){lock_file_path = argv[1];} int fd = 0; assert((fd = open(lock_file_path,"r")) > 0); // 使用文件锁之前须要得到锁文件的file desc assert(0 == flock(fd,LOCK_SH)) // 加上共享锁 char buff[256],str[1024]; bzero(buff,sizeof(buff)); bzero(str,sizeof(str)); size_t rd = 0; while((rd = read(fd,buff,sizeof(buff)-1)) > 0) { buff[rd] = '\0'; strcat(str,buff); } printf("load str from %s is %s\n",lock_file_path,str); flock(fd,LOCK_UN) // 解锁 close(fd); // 如果没有多个 file_description 指向同一个文件,那么可以使用close(fd),隐式解锁,但不建议 return 0; }
// read_1.cc #include <sys/file.h> #include <stdio.h> #include <assert.h> #include <signal.h> #include <stdlib.h> #include <unistd.h> int fd = 0; void signal_handle(int sig){ switch(sig){ case SIGKILL: case SIGQUIT: case SIGINT: case SIGSTOP: if(fd){ flock(fd,LOCK_UN); close(fd); } exit(0); default: return; } } int main(int argc,char* argv[]){ const char* lock_file_path = "flock.lock"; if(argc >= 2){ lock_file_path = argv[1]; } assert((fd = open(lock_file_path,"w")) > 0); signal(SIGKILL,signal_handle); signal(SIGQUIT,signal_handle); signale(SIGINT,signal_handle); while(true){ assert(0 == flock(fd,LOCK_EX)) // 加上排他锁 char *str=nullptr; size_t str_size = 0; getline(&str,&str_size,stdin); write(fd,str,str_size); assert(0 == flock(fd,LOCK_UN)); sleep(2); } return 0; }
- 简易包装成guard
// flock_guard.hpp #include <string> #include <sys/file.h> #include <cassert> class flock_guard{ int fd; public: flock_guard(const std::string& filepath, int lock_type // LOCK_SH 或 LOCK_EX ){ assert((fd = open(filepath.c_str(),"r")) > 0); assert(0 == flock(fd,lock_type)); } virtual ~flock_guard(){ flock(fd,LOCK_UN); close(fd); } }; // 包装读写锁 // read flock guard class rflock_guard : public flock_guard{ public: rflock_guard(const std::string& filepath) :flock_guard(filepath,LOCK_SH) //使用共享锁 作读锁 {} }; // write flock guard class wflock_guard:public flock_guard{ public: wflock_guard(const std::string& filepath) :flock_guard(filepath,LOCK_EX) // 使用排他锁 作写锁 {} };
通过使用flock建立排它锁可以规避这个问题
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示
2014-11-21 PHP 对象和数组互相转换
2012-11-21 Eclipse中集成和调试Ant工程