2015-04-10 2 views
0

Я пишу приложение, в котором два процесса должны обновить один и тот же файл file.txt. Есть вероятность, что это произойдет одновременно, поэтому я должен реализовать некоторую блокировку.Заблокировать файл для чтения и записи

Каждый процесс должен сначала прочитать все file.txt, обработать его, а затем выписать измененную версию file.txt. Таким образом, блокировка должна быть получена до первого чтения файла и выпущена после записи. Я проверил flock в Fcntl, но кажется, что он может заблокировать только дескриптор файла, поэтому блокировка теряется после первого чтения (так как я должен закрыть файл, прежде чем я смогу снова открыть его для записи позже).

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

Как можно реализовать эту схему блокировки? Есть ли модуль CPAN, который я могу использовать?

+3

См [делать блокировки файлов оставаться при использовании открытым во второй раз?] (HTTP: //переполнение стека.com/q/29308727/176646) OP этого вопроса пытался открыть файл в режиме добавления, а затем в режиме чтения/записи, но концепция такая же. – ThisSuitIsBlackNot

+2

данные блокировки являются консультантами в любом случае (в unix), можно ли использовать отдельный файл блокировки? – Sobrique

+0

@Sobrique Да, отдельный файл блокировки кажется хорошей идеей. Интересно, но как реализовать это, чтобы процесс не был занят - ожидал, если файл заблокирован? –

ответ

3

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

Что касается потери блокировки на файл, у вас есть два очевидных варианта

  • получить блокировку на отдельный файл, который существует только для контроля доступа к основному файлу. Это, вероятно, самый удобный способ.

  • Открыть файл с доступом для чтения и записи с использованием режима +<. Это позволит вам прочитать файл, а затем переписать после использования seek и truncate

Каждый процесс должен попытаться получить монопольную блокировку с flock $fh, LOCK_EX, и будет ждать, пока свою очередь, чтобы получить доступ к файлу.

Вы должны использовать

use Fcntl qw/ :flock :seek /; 

импортировать соответствующие константы для этих операций.

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

use strict; 
use warnings; 
use 5.010; 
use autodie; 

use Fcntl qw/ :flock /; 

my ($data_file, $lock_file) = qw/ data.txt lockfile.lock /; 

open my $lock_fh, '<', $lock_file; 
flock $lock_fh, LOCK_EX; 

open my $data_fh, '<', $data_file; 
chomp(my $record = <$data_fh>); 

open $data_fh, '>', $data_file; 
print $data_fh ++$record, "\n"; 

close $data_fh; 

close $lock_fh; 

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

use strict; 
use warnings; 
use 5.010; 
use autodie; 

use Fcntl qw/ :flock :seek /; 

my $data_file = 'data.txt'; 

open my $data_fh, '+<', $data_file; 
flock $data_fh, LOCK_EX; 

chomp(my $record = <$data_fh>); 

seek $data_fh, 0, SEEK_SET; 
truncate $data_fh, 0; 
print $data_fh ++$record, "\n"; 

close $data_fh; 
+0

Да, это похоже на правильный подход. Спасибо! –

+0

В первом фрагменте $ data_file и $ lock_file может быть одним и тем же файлом. Вы могли бы просто «открыть мои $ lock_fh», «<», «$ data_file»; – ikegami