2012-01-14 2 views
8

простой и, казалось бы, надежный способ сделать замок под Баш:Предотвращение распространения блокировки

exec 9>>lockfile 
flock 9 

Однако Баш известно, распространяется такой замок Fd всем раздвоенным вещи, включая выполненные программы и т.д.

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

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

run_some_prog 9>&- 

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

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

ответ

8

Вы можете использовать опцию -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. 
+0

Thx! Именно то, что я искал. – user1050755

+2

Не работает с 'flock 9', это только для команды' flock -o lockfile [args ..] 'case – Tino

1

Невозможно пометить FD как close-on-exec в bash, так что нет, лучшего решения нет.

1

-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" 

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

4

По-видимому flock -o 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 - ваши друзья.

Смежные вопросы