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

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

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

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

15
задан Chris W. 15 July 2019 в 20:41
поделиться

3 ответа

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

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

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
24
ответ дан 1 December 2019 в 01:24
поделиться

кажется, что я нашел более легкое решение: человек lockfile

0
ответ дан 1 December 2019 в 01:24
поделиться

Попробуйте команду 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.

10
ответ дан 1 December 2019 в 01:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: