Подтвердить что ты не робот

Как избежать состояния гонки при использовании файла блокировки, чтобы избежать одновременного запуска двух экземпляров скрипта?

Типичный подход, позволяющий избежать одновременного запуска двух экземпляров одного и того же сценария, выглядит следующим образом:

[ -f ".lock" ] && exit 1
touch .lock
# do something
rm .lock

Есть ли лучший способ заблокировать файлы из сценария оболочки, избегая условия гонки? Должны ли каталоги использоваться вместо?

4b9b3361

Ответ 1

Да, в примере сценария действительно есть условие гонки. Вы можете использовать опцию bash noclobber, чтобы получить сбой в случае гонки, когда между -f и touch -f другой скрипт.

Ниже приведен пример фрагмента кода (вдохновленный этой статьей), который иллюстрирует механизм:

if (set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null; 
then
   # This will cause the lock-file to be deleted in case of a
   # premature exit.
   trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT

   # Critical Section: Here you'd place the code/commands you want
   # to be protected (i.e., not run in multiple processes at once).

   rm -f "$lockfile"
   trap - INT TERM EXIT
else
   echo "Failed to acquire lock-file: $lockfile." 
   echo "Held by process $(cat $lockfile)."
fi

Ответ 2

Попробуйте выполнить команду 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

Один node сражался с другим для блокировки. Когда оба запуска завершены, содержимое файла было 1000. Я пробовал несколько раз и всегда работает!

Примечание. Клиент NFS - это RHEL 5.2, а используемый сервер - NetApp.

Ответ 4

похоже, что я нашел более легкое решение: man lockfile