Я хочу запустить несколько сценариев оболочки Bash параллельно. Однако я хочу избежать гоночных условий. Какие команды Unix действительно атомарные, которые я мог бы использовать для этой цели, и как я могу их использовать?
Я хочу запустить несколько сценариев оболочки Bash параллельно. Однако я хочу избежать гоночных условий. Какие команды Unix действительно атомарные, которые я мог бы использовать для этой цели, и как я могу их использовать?
Ответы:
Если lockfile
он не установлен в вашей системе, он mkdir
выполнит эту работу: это атомарная операция, и она завершится неудачно, если каталог уже существует (если вы не добавили параметр -p
командной строки).
create_lock_or_wait () {
path="$1"
wait_time="${2:-10}"
while true; do
if mkdir "${path}.lock.d"; then
break;
fi
sleep $wait_time
done
}
remove_lock () {
path="$1"
rmdir "${path}.lock.d"
}
#!/bin/bash
# Makes sure we exit if flock fails.
set -e
(
# Wait for lock on /var/lock/.myscript.exclusivelock (fd 200) for 10 seconds
flock -x -w 10 200
# Do stuff
) 200>/var/lock/.myscript.exclusivelock
Это гарантирует, что код между "(" и ")" запускается только одним процессом за раз и что процесс слишком долго ожидает блокировки.
lockf(1)
.
lockf(1)
не работает так, как в этом примере. Он не может принять номер дескриптора файла в качестве аргумента.
lockfile (1) выглядит хорошим кандидатом, хотя имейте в виду, что это часть пакета procmail , который вы, возможно, еще не установили на своем компьютере. Это достаточно популярный пакет, который должен быть упакован для вашей системы, если он еще не установлен. Три из четырех систем, которые я проверил, имеют их, а другая - доступна.
Используя это просто:
#!/bin/sh
LOCKFILE=$HOME/.myscript/lock
mkdir -p `dirname $LOCKFILE`
echo Waiting for lock $LOCKFILE...
if lockfile -1 -r15 $LOCKFILE
then
# Do protected stuff here
echo Doing protected stuff...
# Then, afterward, clean up so another instance of this script can run
rm -f $LOCKFILE
else
echo "Failed to acquire lock! lockfile(1) returned $?"
exit 1
fi
Опции, которые я дал, повторяют попытку каждые 15 секунд. Сбросьте флаг "-r", если хотите, чтобы он ждал вечно.
Системный вызов mkdir()
является атомарным в файловых системах POSIX. Таким образом, использование mkdir
команды таким образом, чтобы она включала ровно один вызов mkdir()
, достигло бы вашей цели. (IOW, не используйте mkdir -p
). Соответствующая разблокировка rmdir
конечно.
Предостережение: mkdir()
не может быть атомарным в сетевых файловых системах.
rmdir
значит , и атомное?
Возможно, команда lockfile сделает то, что вам нужно.
lockfile ~/.config/mylockfile.lock
.....
rm -f important.lock
Если вы работаете только в Unix, используйте fifos. Вы можете записывать рабочие записи в fifo и читать процессы из этого файла, и ваши читатели будут блокировать данные на fifo.
Блокировка файлов в порядке, но для того, что вы описываете, я бы пошел с fifos
Как написано здесь: « Правильная блокировка в сценариях оболочки? », С использованием инструмента FLOM (Free LOck Manager) , сериализация команд и сценариев оболочки становится такой же простой, как запуск
flom -- command_to_serialize
FLOM позволяет вам реализовать более изощренные варианты использования (распределенная блокировка, считыватели / записи, числовые ресурсы и т. Д.), Как описано здесь: http://sourceforge.net/p/flom/wiki/FLOM%20by%20examples/
make(1)
взяла верх? (т.е.make -j 9
если у вас 8 ядер)? Это дает дополнительное преимущество чередования работы с более тонкой детализацией.