如何使用更易读的flock调用实现文件创建互斥?
首先直接给结论:你尝试的那种手动分开调用flock --exclusive和flock --unlock的方式不可行,核心原因是:
当你单独执行flock --exclusive file.txt时,flock会启动一个子shell来持有这个排他锁,一旦这条命令执行完毕(子shell退出),锁会被自动释放。这意味着你后面的文件判断、创建操作,都是在无锁保护的状态下运行的,多个进程还是会同时进入创建分支,照样触发写入冲突。
那有没有可读性更强、不用子shell和文件描述符的写法?当然有,flock本身就提供了更直观的解决方案:
方法1:用flock -c直接执行命令块
flock的-c(或--command)选项可以让你直接指定需要在持锁状态下运行的命令串,flock会自动帮你处理锁的获取与释放,完全不用手动管理文件描述符,写法非常清晰:
flock --exclusive --non-block -c 'if [ ! -f file.txt ]; then echo "Simulate the file creation" > file.txt; fi' /var/lock/mylockfile
参数说明:
--exclusive:获取排他锁,确保同一时间只有一个进程持有锁--non-block(即-n):无法立即获取锁时直接退出,和你原示例的逻辑一致-c后的字符串就是需要锁保护的逻辑,整个逻辑会在flock持锁的环境中运行,锁会在命令执行完成后自动释放
方法2:结合shell函数提升可读性
如果你的业务逻辑比较复杂,把代码封装成shell函数再用flock调用,结构会更清晰:
# 定义业务逻辑函数 ensure_file_exists() { if [ ! -f file.txt ]; then echo 'Simulate the file creation' > file.txt echo "File created by process $$" # 可选:打印进程ID验证唯一性 fi } # 用flock调用函数,确保逻辑在锁保护下执行 flock --exclusive --non-block -c "$(declare -f ensure_file_exists); ensure_file_exists" /var/lock/mylockfile
这里declare -f ensure_file_exists会把函数定义输出为字符串,然后在-c的命令串里先定义函数、再执行。这样锁操作和业务逻辑完全分离,代码可读性和维护性都大幅提升。
补充:为什么原始写法晦涩?
你提到的( flock -n 9 || exit 1; ... ) 9>/var/lock/mylockfile,本质是通过把锁文件绑定到自定义文件描述符(9号),让锁在括号内的子shell执行期间保持有效。这是早期shell没有flock -c选项时的变通方案,但需要理解文件描述符和子shell机制,对新手不友好。而上面的两种方法完全避开了这些晦涩语法,同时保证了逻辑的正确性。
内容的提问来源于stack exchange,提问作者Migwell

