我正在使用下面的脚本对独占锁进行压力测试flock
。
在我的笔记本上,它总是运行良好。
但是当我在台式电脑上运行它时,它可能会随机失败,让两个实例同时运行(获取相同的锁!)。
两者都运行 ubuntu 20.04。
所以我怀疑我的桌面有硬件问题,可能是 RAM?
所以,我的问题是,根据 flock missbehavior 给我的提示,我如何跟踪/确定哪个硬件有缺陷?
我的意思是,flock 能指出哪个硬件有缺陷(或质量低劣)吗?
我如何确认问题:
我获取所有具有与完整路径脚本名称匹配的子命令的 flock 进程(即 flock 应作为子命令执行的命令)。
此外,我记录每个脚本完成的工作,并且在该日志中记录了两个或更多实例同时进行的工作。只有获取锁时才会记录工作。
我是否没有正确配置 flock 以提供独占/唯一锁?
我现在也在另一个终端上使用它:
while true;do date;lslocks |grep flock;sleep 1;done
剧本:
cat >flock.tst.sh;chmod +x flock.tst.sh
#!/bin/bash
LC_NUMERIC=en_US.UTF-8
# HELPERS:
#trash /tmp/flock.tst.log;for((i=0;i<20;i++));do flock.tst.sh&:;done #run this on shell
#pkill -fe flock.tst.sh #end all concurrent children trying to acquire the lock
#while true;do date;lslocks |grep flock;sleep 1;done #use this to check if there is more than one lock acquired, check also the log file to confirm it, and if there is two subsequent WORK on the terminal log, it means a problem happened too
: ${bDaemonizing:=false}
: ${bReport:=false} #help use this to show more log, but will be harder to read it.
: ${bCheck:=false} #help this will let the script check if there is more than one instance working, but it may be slow and make it more difficult to let the problem happen
if ! $bDaemonizing;then
echo "this IS a daemon script, only one instace runnable"
flSelf="`realpath $0`"
#set -x
while ! bDaemonizing=true flock --timeout=$(bc <<< "0.2+0.0$RANDOM") "$flSelf" "$flSelf" "$@";do
if $bCheck;then
strParents="$(nice -n 19 pgrep -f "^flock --timeout=.* $flSelf $flSelf" |tr '\n' ',' |sed -r 's"(.*),"\1"')"
if [[ -n "$strParents" ]];then
anDaemonPid=( $(nice -n 19 pgrep --parent "$strParents" -f "$flSelf") )
if((${#anDaemonPid[*]}>1));then echo "ERROR: more than one daemon, flock failed!? :(";ps --no-headers -o ppid,pid,cmd -p "${anDaemonPid[@]}";fi
if $bReport && ((${#anDaemonPid[*]}==1));then echo "$$:Wait daemon stop running or 'kill ${anDaemonPid[0]}'";fi #could be: "already running, exiting.", but the new instance may have updated parameters that work as intended now.
fi
fi
done
exit #returns w/e flock does
fi
echo "$$:Work:`date`"
for((i=0;i<60;i++));do
echo "`\
echo $i;\
date;\
ps --no-headers -o ppid,pid,stat,state,pcpu,rss,cmd -p "$PPID";\
ps --no-headers -o ppid,pid,stat,state,pcpu,rss,cmd -p "$$";\
`" >>/tmp/flock.tst.log
sleep 1
done
echo "$$:Done:`date`"
一些结果:
如您所见,独占锁同时被进程 1458428(flock:1458427)和 1438949(flock:1438941)获取 :(
日志文件(由脚本创建)显示了此问题(在第 50 秒,发生了不应该获取锁的其他实例的第 2 秒日志):
2
Fri 22 Jan 17:03:16 -03 2021
1438953 1458427 S S 0.0 784 flock --timeout=.22377 /home/myUser/bin/flock.tst.sh /home/myUser/bin/flock.tst.sh
1458427 1458428 S S 0.0 3852 /bin/bash /home/myUser/bin/flock.tst.sh
50
Fri 22 Jan 17:03:16 -03 2021
1438925 1438941 S S 0.0 788 flock --timeout=.229687 /home/myUser/bin/flock.tst.sh /home/myUser/bin/flock.tst.sh
1438941 1438949 S S 0.0 3900 /bin/bash /home/myUser/bin/flock.tst.sh
lslock
date
显示这一点(脚本上的while 与is 作为提示):
Fri 22 Jan 17:03:16 -03 2021
flock 1459088 FLOCK 1.8K WRITE* 0 0 0 /home/myUser/bin/flock.tst.sh
flock 1458427 FLOCK 1.8K WRITE 0 0 0 /home/myUser/bin/flock.tst.sh
flock 1438941 FLOCK 1.8K WRITE 0 0 0 /home/myUser/bin/flock.tst.sh (deleted)
Fri 22 Jan 17:03:17 -03 2021
flock 1459616 FLOCK 1.8K WRITE* 0 0 0 /home/myUser/bin/flock.tst.sh
flock 1458427 FLOCK 1.8K WRITE 0 0 0 /home/myUser/bin/flock.tst.sh
flock 1438941 FLOCK 1.8K WRITE 0 0 0 /home/myUser/bin/flock.tst.sh (deleted)
终端日志(产生了许多并发实例)显示以下内容:
1438949:Work:Fri 22 Jan 17:02:23 -03 2021
1458428:Work:Fri 22 Jan 17:03:14 -03 2021
1438949:Done:Fri 22 Jan 17:03:26 -03 2021
1476209:Work:Fri 22 Jan 17:04:02 -03 2021
1458428:Done:Fri 22 Jan 17:04:17 -03 2021
答案1
假设:就在事情发生之前,你保存了脚本。你的编辑器保存了一份副本,然后将副本移到了原始路径。参见Vim 如何做到这一点和为什么。
实际上,旧文件(inode)上仍保留着旧锁。这…/flock.tst.sh (deleted)
在 的输出中显示为lslocks
。但是flock
,您的脚本(它的另一个实例?)不断生成使用该路径。当该路径开始指向另一个 inode 时,允许一些新文件flock
获取新锁。这…/flock.tst.sh
在 的输出中显示为lslocks
。
这两把锁是独立的,它们不能互相阻挡,因为它们使用不同的文件。Flock 按照设计运行。
我实际上可以通过运行脚本的两个实例(一个获取锁,另一个继续尝试获取锁)来重现您的结果,然后立即vim
使用 ( ) 打开它。或者::w
cp flock.tst.sh foo
mv foo flock.tst.sh