Безопасность: при открытии канала передачи нежелательные могут использовать его также. В частности, при использовании виртуальной машины для содержания недоверяемой операционной системы или приложения, гостевые дополнения представляют несколько рисков.
Я предпочел бы управлять управлением числа с внешней стороны и просто называть сценарий, передающий его текущее число как параметр:
n=10
read nr < number.file
seq $((nr+1)) 120 | xargs -n 1 -P $n script.sh
Где сам сценарий был бы уменьшен до чего-то вроде этого:
#!/bin/ksh
number=$1
echo "Do job with/for number $number"
echo $number > number.file
sleep 10
Конечно, если продолжительность задачи может варьироваться, затем лучше для проверки текущего содержания файла числа прежде, чем записать в него, таким образом, не перезаписать больший. Но это важно, только если последовательность задач должна поддерживать вид возобновления.
Выполнение этого без lockfile, казалось бы, потребовало бы чего-то странного, потому что lockfile (еще лучше, каталог блокировки, поскольку создание каталога, как предполагается, является атомарным) является стандартом и осуществимым решением этой проблемы. Я не сделал точно, что Вы хотите сделать, но здесь являетесь некоторыми идеями, которые происходят со мной:
Вы могли записать маленькую программу C для проверки состояния семафора SysV. Запустите с man semget
или man semop
. Это будет утомительно и причудливо.
Вы могли использовать Oracle sqlplus
и блок МН / SQL, который делает:
lock table table_name in exclusive mode
И затем другой вызов sqlplus
выпускать блокировку. Я сделал такую вещь прежде, необходимо проявить большую заботу, чтобы не оставить ожидание процессов и выпустить блокировку. Я также, возможно, только интересовался выполнением работы над таблицей, таким образом, у меня только был один вызов к sqlplus
.
Далее на левой стороне поля, Вы смогли использовать именованные каналы в качестве блокировок взаимного исключения. Необходимо было бы действительно экспериментировать с этим.
Если можно загрузить модуль ядра, возможно, модуль ядра мог бы использовать a /proc
виртуальный файл для действия как взаимное исключение или семафор. IBM developerWorks имеет статью о загружаемом модуле, который создает /proc
файлы.
Возможно, Вы могли реализовать алгоритм Dekker со значениями в файлах или именованных каналах.
После рассмотрения, что я записал, я не слишком уверен что любой из них кроме выполнения программы C semop()
действительно работал бы. Они все требуют большого экспериментирования.
Предположения:
Можно использовать атомарные операции, такие как создание файла (set -C; (: >foo) 2>/dev/null
), переименование (mv
) и удаление (rm
) обработать блокировку.
Для уведомления процесса можно отправить ему сигнал; однако это проблематично для определения местоположения целевых процессов: при хранении идентификаторов процесса где-нибудь Вы не можете быть уверены, что идентификаторы все еще действительны, они, возможно, были снова использованы несвязанным процессом. Один способ синхронизировать два процесса состоит в том, чтобы записать байт на канале; читатель заблокируется, пока устройство записи не подойдет и наоборот.
Во-первых, настройте каталог. Создайте названный файл lock
и названный именованный канал pipe
.
if ! [ -d /script-locking-directory ]; then
# The directory doesn't exist, create and populate it
{
mkdir /script-locking-directory-$$ &&
mkfifo /script-locking-directory-$$/pipe &&
touch /script-locking-directory-$$/lock &&
mv /script-locking-directory-$$ /script-locking-directory
} || {
# An error happened, so clean up
err=$?
rm -r /script-locking-directory-$$
# Exit, unless another instance of the script created the directory
# at the same time as us
if ! [ -d /script-locking-directory ]; then exit $?; fi
}
fi
Мы реализуем взятие блокировки путем переименования lock
файл. Кроме того, мы будем использовать простой план уведомить всех официантов относительно блокировки: повторите байт к каналу и имейте всех официантов, ожидают путем чтения из того канала. Вот простая схема.
take_lock () {
while ! mv lock lock.held 2>/dev/null; do
read <pipe # wait for a write on the pipe
done
}
release_lock () {
mv lock.held lock
read <pipe & # make sure there is a reader on the pipe so we don't block
echo >pipe # notify all readers
}
Эта схема будит всех официантов, которые могут быть неэффективными, но это не будет проблемой, если не будет много конкуренции (т.е. много официантов одновременно).
Основная проблема с кодом выше состоит в том, что, если держатель блокировки умирает, блокировка не будет выпущена. Как мы можем обнаружить ту ситуацию? Мы не можем только пойти, ища процесс, названный как блокировка из-за повторного использования PID. То, что мы можем сделать, открыть файл блокировки в сценарии и проверку, если файл блокировки открыт, когда новый экземпляр сценария запускается.
break_lock () {
if ! [ -e "lock.held" ]; then return 1; fi
if [ -n "$(fuser lock.held)" ]; then return 1; fi
# If we get this far, the lock holder died
if mv lock.held lock.breaking.$$ 2>/dev/null; then
# Check that someone else didn't break the lock and take it just now
if [ -n "$(fuser lock.breaking.$$)" ]; then
mv lock.breaking.$$ lock.held
return 0
fi
mv lock.breaking.$$ lock
fi
return 0 # whether we did break a lock or not, try taking it again
}
take_lock () {
while ! mv lock lock.taking.$$ 2>/dev/null; do
if break_lock; then continue; fi
read <pipe # wait for a write on the pipe
done
exec 9<lock.taking.$$
mv lock.taking.$$ lock.held
}
release_lock () {
# lock.held might not exist if someone else is trying to break our lock.
# So we try in a loop.
while ! mv lock.held lock.releasing.$$ 2>/dev/null; do :; done
exec 9<&-
mv lock.releasing.$$ lock
read <pipe & # make sure there is a reader on the pipe so we don't block
echo >pipe # notify all readers
}
Эта реализация может все еще зайти в тупик, если держатель блокировки умирает, в то время как другой экземпляр внутри take_lock
: блокировка останется сохраненной, пока третий экземпляр не запустится. Я также предполагаю, что сценарий не умрет внутри take_lock
или release_lock
.
Предупреждение: Я написал код выше непосредственно в браузере, я не протестировал его (уже не говоря о доказанном, который он исправляет).
take_lock
и release_lock
вокруг критического раздела Вашего кода, как обычно, с блокировкой.
– Gilles 'SO- stop being evil'
16.01.2012, 20:19
lock.heid
не появляется нигде в моем сообщении. спасибо
– Gilles 'SO- stop being evil'
16.01.2012, 23:01
xargs
'говорит о-P
(--max-procs
) опция: “Дошедший макс.-procs обрабатывает за один раз; значение по умолчанию равняется 1”. Так, чтобы код запустил процессы $n, передав следующий порядковый номер каждому как параметр. Как только один из процессов завершается, новый запускается, передавая его следующий порядковый номер. И так далее, пока последовательность чисел не закончена. – manatwork 13.01.2012, 10:28-P
была сущность. Спасибо за то, что сообщили мне о его отсутствии на Unix. Другая команда, способная для выполнения параллельных задач,make
с-j
(--jobs
) опция, но возможный быть расширением GNU. Так или иначе, мойmake
знание слишком слабо для создания этого ответом. – manatwork 13.01.2012, 19:00