2017-01-26 4 views
1

Один из моих скриптов - установка компонента. При параллельном запуске один и тот же скрипт пытается установить один и тот же компонент, поэтому я подумал о синхронизации процесса, заблокировав файл во время установки скрипта и дожидаясь, пока другой скрипт что-то устанавливает.Синхронизация процессов путем блокировки файла

код будет выглядеть следующим образом:

# this will create a file handler on a file from TEMP dir with the 
# name of the component; if it doesn't exist in TEMP dir, it will create it 

my $file = $ENV{"TEMP"}. "\\" . $componentName; 
open (my $fh, ">", "$file") or die "Couldn't open file!"; 

# this will apply an exclusive lock meaning that if another process 
# already locked the file, it will wait until the lock is removed 

flock($fh, 2) or die "Failed to lock the file"; 

# install the component.. 

# closing the file handle automatically removes the lock 
close $fh; 

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

Будет ли проблема с этим?

+3

Это, вероятно, лучше для читаемости, если вы используете именованные константы вместо «2» в своем вызове «flock». Также вы, вероятно, хотите иметь значение по умолчанию для '$ ENV {TEMP}' и убедитесь, что ваш 'open' успешно. Вероятно, вы захотите также проверить возвращаемое значение 'flock'. – jcaron

+0

@jcaron Вы правы, спасибо за предложения, я использую явное имя констант, также рассматривая исключения, которые могут возникать при открытии или блокировке файла. –

ответ

4

Важно помнить, что «открытая» будет работать в любом случае, потому что это не проверяет блокировку. Это операция flock, которая будет блокироваться до тех пор, пока блокировка не будет отпущена.

И это должно работать нормально, хотя после того, как освобожден - вы можете проверить, нужно ли все же выполнить установку, если только вам не нужно делать это дважды - например. если остальная часть скрипта использует/полагается на него.

Также есть ли другие источники «установки», которые не являются вашим скриптом, что может вызвать такую ​​же проблему? Замок - это консультативная вещь.

Было бы улучшение стиля в вашей программе также:

  • Теста $ENV{'TEMP'} увидеть, что она существует, и по умолчанию (или не), если он не делает.
  • use Fcntl qw (:flock); потому что тогда вы можете flock ($fh, LOCK_EX);, чтобы было ясно, что вы делаете эксклюзивный замок.
  • В качестве разделителя файлов вы используете \\. Вероятно, это лучше, если вы использовали что-то вроде File::Spec, чтобы сделать это по причинам мобильности.
  • Вы можете использовать LOCK_NB для неблокирования: flock ($fh, LOCK_EX | LOCK_NB), а затем просто пропустить, если он заблокирован.
+0

Вы правы, я проверяю, если компонент уже был установлен другим скриптом. –

+0

Это единственная проблема, с которой я столкнулся, если блокировка влияет на функцию 'open' –

+0

@JohnDoe: вы могли бы просто [прочитать об этом] (http://perldoc.perl.org/functions/flock.html) – Borodin

2

Блокировка не препятствует открытию или изменению файла; это предотвращает его блокировку.

Это означает, что open не подведет, и он будет сжимать файл, даже если он заблокирован и все еще используется. Если блокировка предназначена для защиты доступа к файлу (т. Е. Если программы фактически записываются в заблокированный файл), вы хотите использовать sysopen, чтобы избежать сглаживания файла, если он уже существует [1].

use Fcntl qw(LOCK_EX O_CREAT O_WRONLY); 

# Open the file without clobbering it, creating it if necessary. 
sysopen(my $fh, $qfn, O_WRONLY | O_CREAT) 
    or die($!); 

# Wait for the file to become available. 
flock($fh, LOCK_EX) 
    or die($!); 

truncate($fh, 0) 
    or die($!); 

... 

или

use Fcntl qw(LOCK_EX LOCK_NB O_CREAT O_WRONLY); 

# Open the file without clobbering it, creating it if necessary. 
sysopen(my $fh, $qfn, O_WRONLY | O_CREAT) 
    or die($!); 

# Check if the file is locked. 
flock($fh, LOCK_EX | LOCK_NB) 
    or die($!{EWOULDBLOCK} ? "File already in use\n" : $!); 

truncate($fh, 0) 
    or die($!); 

... 

  1. Вы можете также использовать open(my $fh, '>>', $qfn), если вы не против того, файл в режиме добавления.
+1

Отлично, спасибо. Поэтому я сначала открываю файл, а затем жду, используя 'sysopen'. Я полагаю, что тогда «открыто» для чтения отлично (тогда ждите). – zdim

+0

Спасибо за ответ, очень хорошее объяснение! Я проигнорирую проблему clobber, потому что это не важная часть в моем алгоритме. Важная часть - синхронизация установок, файл - просто пешка в этой шахматной игре. Я использую его как флаг. Пока он заблокирован, не выполняйте установку. Если файл не заблокирован, я могу установить его. –

+0

Ах да. Я добавлю комментарий по этому поводу к моему ответу. – ikegami

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