Состояние гонки в общей блокировке файла?
Это стандартный подход для создания блокировок с использованием файловой системы. Например, Visudo использует это:
[ -f ".lock" ] && exit 1
touch .lock
# do something
rm .lock
1) Я запутался, потому что есть условие гонки, но Linux использует его
2) есть ли лучший способ заблокировать файлы из оболочки?
3) или я должен вместо этого использовать каталоги?
Найденное решение: man lockfile.
4 ответа
Да, в примере сценария действительно есть условие гонки. Вы можете использовать опцию bash noclobber, чтобы получить сбой в случае гонки, когда между тестом и касанием проскальзывает другой скрипт.
Это описано здесь. Я выдержал критическую часть с парой аннотаций (с префиксом BK:):
Возможное решение этой проблемы - использовать перенаправление ввода-вывода и режим boc noclobber, который не будет перенаправлять на существующий файл. Мы можем использовать что-то похожее на:
if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null;
then
# BK: this will cause the lock file to be deleted in case of other exit
trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT
# critical-section BK: (the protected bit)
rm -f "$lockfile"
trap - INT TERM EXIT
else
echo "Failed to acquire lockfile: $lockfile."
echo "Held by $(cat $lockfile)"
fi
Попробуйте команду flock:
exec 200>"$LOCK_FILE"
flock -e -n 200 || exit 1
Он выйдет, если файл блокировки заблокирован. Он атомарный и будет работать над последней версией NFS.
Я сделал тест. Я создал файл счетчика с 0 в нем и выполнил следующее в цикле на двух серверах одновременно 500 раз:
#!/bin/bash
exec 200>/nfs/mount/testlock
flock -e 200
NO=`cat /nfs/mount/counter`
echo "$NO"
let NO=NO+1
echo "$NO" > /nfs/mount/counter
Один узел сражался с другим за замок. Когда оба запуска закончились, содержимое файла было 1000. Я пробовал несколько раз, и это всегда работает!
Примечание. NFS-клиент - RHEL 5.2, а используемый сервер - NetApp.
Блокировка вашего скрипта (против параллельного запуска)
http://wiki.bash-hackers.org/howto/mutex
FYI.
Создание каталога является атомарным и не работает, если он уже существует, если вы не используете -p
, так
mkdir $lockName || exit 1
работает.
... но используйте flock
вместо.