Синхронизировать выполнение сценария оболочки

Модифицированная версия сценария оболочки преобразует аудиофайл из FLAC в формат MP3. Компьютер имеет четырехъядерный процессор. Скрипт запускается с использованием:

./flac2mp3.sh $(find flac -type f)

Это преобразует файлы FLAC в flac каталог (без пробелов в именах файлов) для файлов MP3 в mp3 каталог (на том же уровне, что и flac). Если целевой файл MP3 уже существует, скрипт пропускает файл.

Проблема заключается в том, что иногда два экземпляра сценария проверяют наличие одного и того же файла MP3 практически в одно и то же время, что приводит к искажению файлов MP3.

Как бы вы запустили сценарий несколько раз (т. Е. Один раз для каждого ядра), без необходимости указывать другой набор файлов в каждой командной строке и без перезаписи работы?

Обновление - Минимальные условия гонки

Скрипт использует следующий механизм блокировки:

  # Convert FLAC to MP3 using tags from flac file.
  #
  if [ ! -e $FLAC.lock ]; then
    touch $FLAC.lock
    flac -dc "$FLAC" | lame${lame_opts} \
      --tt "$TITLE" \
      --tn "$TRACKNUMBER" \
      --tg "$GENRE" \
      --ty "$DATE" \
      --ta "$ARTIST" \
      --tl "$ALBUM" \
      --add-id3v2 \
      - "$MP3"
    rm $FLAC.lock
  fi;

Тем не менее, это все еще оставляет условие гонки.

8 ответов

Решение

Команда "lockfile" предоставляет то, что вы пытаетесь сделать для сценариев оболочки без условия гонки. Команда была написана людьми procmail специально для такого рода целей и доступна в большинстве систем BSD/Linux (так как procmail доступен для большинства сред).

Ваш тест становится примерно таким:

lockfile -r 3 $FLAC.lock
if test $? -eq 0 ; then
  flac -dc "$FLAC" | lame${lame_opts} \
    --tt "$TITLE" \
    --tn "$TRACKNUMBER" \
    --tg "$GENRE" \
    --ty "$DATE" \
    --ta "$ARTIST" \
    --tl "$ALBUM" \
    --add-id3v2 \
    - "$MP3"
fi
rm -f $FLAC.lock

В качестве альтернативы, вы можете сделать так, чтобы lockfile продолжал повторяться до бесконечности, поэтому вам не нужно проверять код возврата, и вместо этого вы можете проверить выходной файл, чтобы определить, следует ли запускать flac.

Если у вас нет lockfile и не может установить его (в любой из его версий - есть несколько реализаций) надежный и переносимый атомный мьютекс mkdir,

Если каталог, который вы пытаетесь создать, уже существует, mkdir потерпит неудачу, так что вы можете проверить это; Когда создание завершается успешно, у вас есть гарантия, что ни один другой процесс сотрудничества не окажется в критической секции одновременно с вашим кодом.

if mkdir "$FLAC.lockdir"; then
    # you now have the exclusive lock
    : critical section
    : code goes here
    rmdir "$FLAC.lockdir"
else
    : nothing? to skip this file
    # or maybe sleep 1 and loop back and try again
fi

Для полноты, может быть, также искать flock если вы находитесь на наборе платформ, где это надежно доступно и вам нужна эффективная альтернатива lockfile,

Вы можете реализовать блокировку файлов FLAC, над которыми он работает. Что-то вроде:

if (not flac locked)
  lock flac
  do work
else
  continue to next flac

Отправьте вывод во временный файл с уникальным именем, затем переименуйте файл в нужное имя.

flac -dc "$FLAC" | lame${lame_opts} \
      --tt "$TITLE" \
      --tn "$TRACKNUMBER" \
      --tg "$GENRE" \
      --ty "$DATE" \
      --ta "$ARTIST" \
      --tl "$ALBUM" \
      --add-id3v2 \
      - "$MP3.$$"
mv "$MP3.$$" "$MP3"

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

Чтобы заблокировать файловый процесс, вы можете создать файл с тем же именем и расширением.lock.

Перед началом кодирования проверьте наличие файла.lock и при необходимости убедитесь, что дата файла блокировки не слишком старая (в случае, если процесс умирает). Если он не существует, создайте его до начала кодирования и удалите его после завершения кодирования.

Вы также можете скопировать файл, но это действительно работает только в c, где вы вызываете flock() и записываете в файл, затем закрываете и разблокируете. Для сценария оболочки вы, вероятно, вызываете другую утилиту для написания файла.

В bash можно установить опцию noclobber, чтобы избежать перезаписи файла.

набор помощи | egrep 'noclobber|-C'

Как насчет написания Makefile?

ALL_FLAC=$(wildcard *.flac)
ALL_MP3=$(patsubst %.flac, %.mp3, $(ALL_FLAC)
all: $(ALL_MP3)
%.mp3: %.flac
        $(FLAC) ...

Тогда делай

$ make -j4 all

Используйте такой инструмент, как FLOM (Free LOck Manager) и просто сериализуйте вашу команду, как показано ниже:

flom -- flac ....
Другие вопросы по тегам