Я использую приведенный ниже скрипт для стресс-теста монопольной блокировки с помощью flock
.
На моем ноутбуке он всегда работает нормально.
Но когда я запускаю его на своем настольном ПК, он может случайно дать сбой, позволяя двум экземплярам работать одновременно (получая одну и ту же блокировку!).
Оба работают под управлением Ubuntu 20.04.
Итак, я подозреваю, что проблема связана с оборудованием моего компьютера. Может быть, с оперативной памятью?
Итак, мой вопрос, основываясь на совете, который дает мне 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
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
показывает это (while date
находится в скрипте как подсказка):
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