Состояние гонки в общей блокировке файла?

Это стандартный подход для создания блокировок с использованием файловой системы. Например, 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 вместо.

Кажется, я нашел более простое решение: man lockfile

Другие вопросы по тегам