Как синхронизировать (блокировать/разблокировать) доступ к файлу в bash из нескольких сценариев?
Я пишу скрипты, которые будут запускаться параллельно, и получат их входные данные из того же файла. Эти сценарии откроют входной файл, прочитайте первую строку, сохраните его для дальнейшего лечения и, наконец, удалите эту строку чтения из входного файла.
Теперь проблема в том, что несколько сценариев, обращающихся к файлу, могут привести к ситуации, когда два сценария одновременно получают доступ к входному файлу и считывают одну и ту же строку, что приводит к недопустимому результату обработки строки дважды.
Теперь одно решение - записать файл блокировки (.lock_input
) перед доступом к входному файлу, а затем стереть его при выпуске входного файла, но это решение не привлекательно в моем случае, потому что иногда NFS замедляет сетевую связь в случайном порядке и может не иметь надежной блокировки.
Другим решением является установка блокировки процесса вместо записи файла, что означает, что первый script для доступа к входному файлу запустит процесс с именем lock_input, а остальные скрипты будут ps -elf | grep lock_input
. Если он присутствует в списке процессов, они будут ждать. Это может быть быстрее, чем запись в NFS, но все еще не идеальное решение...
Итак, мой вопрос: есть ли какая-либо команда bash (или другой интерпретатор script) или служба, которую я могу использовать, которая будет вести себя как блокировки семафора или мьютекса, используемые для синхронизации в программировании потоков
Спасибо.
Небольшой пример:
Скажем, у нас есть input_file, как показано ниже:
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
Лечение script: TrScript.sh
#!/bin/bash
NbLines=$(cat input_file | wc -l)
while [ ! $NbLines = 0 ]
do
FirstLine=$(head -1 input_file)
echo "Hello World today is $FirstLine"
RemainingLines=$(expr $NbLines - 1 )
tail -n $RemainingLines input_file > tmp
mv tmp input_file
NbLines=$(cat input_file | wc -l)
done
Основной script:
#! /bin/bash
./TrScript.sh &
./TrScript.sh &
./TrScript.sh &
wait
Результат должен быть:
Hello World today is Monday
Hello World today is Tuesday
Hello World today is Wednesday
Hello World today is Thursday
Hello World today is Friday
Hello World today is Saturday
Hello World today is Sunday
Ответы
Ответ 1
Мне всегда нравилась программа lockfile (образец результата поиска для файл блокировки файла) из набора инструментов procmail (должен быть доступен в большинстве систем, хотя он не может быть установлен по умолчанию).
Он был предназначен для блокировки почтовых файлов спула, которые (были?) обычно монтируются через NFS, поэтому он корректно работает над NFS (насколько это возможно).
Кроме того, до тех пор, пока вы делаете предположение, что все ваши "рабочие" находятся на одной машине (предполагая, что вы можете проверить PID, что может не работать должным образом, когда PID в конечном итоге завершают), вы можете поместить свой файл блокировки в каком-либо другом локальном каталоге (например,/tmp) при обработке файлов, размещенных на сервере NFS. До тех пор, пока все рабочие используют одно и то же расположение файла блокировки (и сопоставление "один-к-одному" имен файлов блокировки с заблокированными именами путей), он будет работать нормально.
Ответ 2
использование
line=`flock $lockfile -c "(gawk 'NR==1' < $infile ; gawk 'NR>1' < $infile > $infile.tmp ; mv $infile.tmp $infile)"`
для доступа к файлу, который вы хотите прочитать. Это использует блокировки файлов.
gawk NR==1 < ...
выводит первую строку ввода
Ответ 3
Используя инструмент FLOM (Free LOck Manager), ваш основной script может стать таким же простым, как:
#!/bin/bash
flom -- ./TrScript.sh &
flom -- ./TrScript.sh &
flom -- ./TrScript.sh &
wait
если вы используете script внутри одного хоста и что-то вроде:
flom -A 224.0.0.1 -- ./TrScript.sh &
если вы хотите распространять свой script на многих хостах. Некоторые примеры использования доступны по этому URL-адресу: http://sourceforge.net/p/flom/wiki/FLOM%20by%20examples/