Предотвращение распространения блокировки - PullRequest
8 голосов
/ 15 января 2012

Простой и, казалось бы, надежный способ сделать блокировку под bash:

exec 9>>lockfile
flock 9

Однако bash, как известно, распространяет такую ​​блокировку fd на все разветвленные объекты, включая исполняемые программы и т. Д.

IsЕсть ли способ сказать Bash, чтобы не дублировать FD?Замечательно, что блокировка прикреплена к fd, который удаляется после завершения программы, независимо от того, как она завершается.

Я знаю, что могу делать такие вещи, как:

run_some_prog 9>&-

Но этодовольно утомительно.

Есть ли лучшее решение?

Ответы [ 4 ]

8 голосов
/ 15 января 2012

Вы можете использовать параметр командной строки -o для flock(1) (длинный параметр --close, который может быть лучше для записи в скриптах для самодокументируемой природы), чтобы указать, что дескриптор файла должен быть закрыт перед выполнениемкоманды через flock(1):

   -o, --close
          Close the file descriptor on which the lock is held
          before executing command.  This is useful if command
          spawns a child process which should not be holding
          the lock.
4 голосов
/ 08 августа 2012

Видимо flock -o FD не решает проблему. Уловка, чтобы избавиться от лишнего FD для более поздних команд в том же самом сценарии оболочки, состоит в том, чтобы обернуть оставшуюся часть в раздел, который закрывает FD, как это:

var=outside

exec 9>>lockfile
flock -n 9 || exit
{

: commands which do not see FD9

var=exported
# exit would exit script

# see CLUMSY below outside this code snippet
} 9<&-
# $var is "exported"

# drop lock closing the FD
exec 9<&-

: remaining commands without lock

Это бит CLUMSY, потому что закрытие FD так далеко отделено от блокировки.

Вы можете изменить это, потеряв «естественный» поток команд, но собрав вместе вещи, которые принадлежат друг другу:

functions_running_with_lock()
{
: commands which do not see FD9

var=exported
# exit would exit script
}

var=outside

exec 9>>lockfile
flock -n 9 || exit

functions_running_with_lock 9<&-

# $var is "exported"

# drop lock closing the FD
exec 9<&-

: remaining commands without lock

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

var=outside

exec 9>>lockfile
flock -n 9 || exit
(
exec 9<&-

: commands which do not see FD9

var=exported
# exit does not interrupt the whole script
exit
var=neverreached
)
# optionally test the ret if the parentheses using $?

# $var is "outside" again

# drop lock closing the FD
exec 9<&-

: remaining commands without lock

Кстати, если вы действительно хотите быть уверены, что bash не вводит дополнительные файловые дескрипторы (чтобы «спрятать» закрытый FD и пропустить реальный форк), например, если вы выполняете какой-то демон, который затем удерживает блокировку навсегда, последний вариант рекомендуется, просто чтобы быть уверенным. lsof -nP и strace your_script ваши друзья.

1 голос
/ 19 апреля 2012

-o не работает с файловыми дескрипторами, он работает только с файлами. Вы должны использовать -u, чтобы разблокировать дескриптор файла.

Что я делаю, это:

# start of the lock sections
LOCKFILE=/tmp/somelockfile
exec 8>"$LOCKFILE"
if ! flock -n 8;then
      echo Rejected  # for testing, remove this later
      exit           # exit, since we don't have lock
fi

# some code which shouldn't run in parallel

# End of lock section
flock -u 8
rm -f "$LOCKFILE"

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

1 голос
/ 15 января 2012

Нет способа пометить FD как близкий к exec в bash, так что нет, лучшего решения нет.

...