Какие команды Unix можно использовать как семафор / блокировку?

34

Я хочу запустить несколько сценариев оболочки Bash параллельно. Однако я хочу избежать гоночных условий. Какие команды Unix действительно атомарные, которые я мог бы использовать для этой цели, и как я могу их использовать?

Ларри Ван
источник
Что вы делаете, что требует параллельной работы? Разве вы не можете выразить зависимости таким образом, чтобы параллель make(1)взяла верх? (т.е. make -j 9если у вас 8 ядер)? Это дает дополнительное преимущество чередования работы с более тонкой детализацией.
vonbrand

Ответы:

30

Если lockfileон не установлен в вашей системе, он mkdirвыполнит эту работу: это атомарная операция, и она завершится неудачно, если каталог уже существует (если вы не добавили параметр -pкомандной строки).

create_lock_or_wait () {
  path="$1"
  wait_time="${2:-10}"
  while true; do
        if mkdir "${path}.lock.d"; then
           break;
        fi
        sleep $wait_time
  done
}

remove_lock () {
  path="$1"
  rmdir "${path}.lock.d"
}
Риккардо Мурри
источник
26

flock(1)

#!/bin/bash

# Makes sure we exit if flock fails.
set -e

(
  # Wait for lock on /var/lock/.myscript.exclusivelock (fd 200) for 10 seconds
  flock -x -w 10 200

  # Do stuff

) 200>/var/lock/.myscript.exclusivelock

Это гарантирует, что код между "(" и ")" запускается только одним процессом за раз и что процесс слишком долго ожидает блокировки.

Алекс Б
источник
Хороший, не знал об этом. Тем не менее, это, по-видимому, специфично для Linux ...
Риккардо Мурри
1
@Riccardo, FreeBSD имеет аналогичную команду: lockf(1).
Алекс Б
lockf(1)не работает так, как в этом примере. Он не может принять номер дескриптора файла в качестве аргумента.
Чарли
11

lockfile (1) выглядит хорошим кандидатом, хотя имейте в виду, что это часть пакета procmail , который вы, возможно, еще не установили на своем компьютере. Это достаточно популярный пакет, который должен быть упакован для вашей системы, если он еще не установлен. Три из четырех систем, которые я проверил, имеют их, а другая - доступна.

Используя это просто:

#!/bin/sh
LOCKFILE=$HOME/.myscript/lock
mkdir -p `dirname $LOCKFILE`

echo Waiting for lock $LOCKFILE...
if lockfile -1 -r15 $LOCKFILE
then
    # Do protected stuff here
    echo Doing protected stuff...

    # Then, afterward, clean up so another instance of this script can run
    rm -f $LOCKFILE
else
    echo "Failed to acquire lock!  lockfile(1) returned $?"
    exit 1
fi

Опции, которые я дал, повторяют попытку каждые 15 секунд. Сбросьте флаг "-r", если хотите, чтобы он ждал вечно.

Уоррен Янг
источник
2
Просто для справки - справочная страница: linux.die.net/man/1/lockfile . :)
Лукас Джонс
Помните, что (в соответствии с man-страницей): «Как только файл заблокирован, к блокировке нужно прикасаться не реже одного раза в пять минут, иначе блокировка будет считаться устаревшей, и последующие попытки блокировки будут успешными».
Джей
6

Системный вызов mkdir()является атомарным в файловых системах POSIX. Таким образом, использование mkdirкоманды таким образом, чтобы она включала ровно один вызов mkdir(), достигло бы вашей цели. (IOW, не используйте mkdir -p). Соответствующая разблокировка rmdirконечно.

Предостережение: mkdir()не может быть атомарным в сетевых файловых системах.

Хари
источник
это rmdirзначит , и атомное?
Алексей Магура
3

Возможно, команда lockfile сделает то, что вам нужно.

lockfile ~/.config/mylockfile.lock
.....
rm -f important.lock
jacksonh
источник
Это похоже на удаление неправильного файла.
Бенджамин В.
1

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

Блокировка файлов в порядке, но для того, что вы описываете, я бы пошел с fifos

Крис
источник
1
Не могли бы вы рассказать о том, как, по вашему мнению, fifos может предотвратить условия гонки?
G-Man говорит: «Восстановите Монику»
0

Как написано здесь: « Правильная блокировка в сценариях оболочки? », С использованием инструмента FLOM (Free LOck Manager) , сериализация команд и сценариев оболочки становится такой же простой, как запуск

flom -- command_to_serialize

FLOM позволяет вам реализовать более изощренные варианты использования (распределенная блокировка, считыватели / записи, числовые ресурсы и т. Д.), Как описано здесь: http://sourceforge.net/p/flom/wiki/FLOM%20by%20examples/

tiian
источник