Есть ли способ создать файл, который заблокирован в момент создания, в Perl?
Мне нужно создать файл, который заблокирован от чтения, в момент создания, чтобы другие процессы, которые могут искать этот файл, не начали читать его до того, как он будет полностью записан.
Я знаю, что могу создать и затем заблокировать его, но я обеспокоен тем, что это оставляет меня открытым для состояния гонки.
Или я здесь ни о чем не беспокоюсь? Если у меня есть файл, открытый для записи, а затем открыть его для чтения другим процессом, будет ли процесс чтения никогда не видеть EOF, пока процесс записи не закроет файл?
3 ответа
Есть условие гонки с >
а также >>
, но это можно обойти, используя +<
,
# >
open(my $fh, '+<', $qfn) or die $!;
flock($fh, LOCK_EX) or die $!;
truncate($fh, 0) or die $!;
...
# >>
open(my $fh, '+<', $qfn) or die $!;
flock($fh, LOCK_EX) or die $!;
seek($fh, 0, SEEK_END) or die $!;
...
В сценарии, который вы описываете, есть и состояние гонки.
Writer Reader
========================= =========================
- opens file
- opens file
- locks file
- obtains lock on file
- locks file [blocks] - reads the file [empty]
- closes and unlocks file
- obtains lock on file
- writes to file
- writes to file
- closes and unlocks file
Общая стратегия, чтобы избежать этой проблемы, состоит в том, чтобы иметь автора
- создайте файл во временном каталоге, а затем
rename
файл в каталог, который читатель отслеживает, когда файл завершен.
rename
это атомарное действие, поэтому файл будет выглядеть полностью сформированным в каталоге, который отслеживает читатель. Это требует сотрудничества писателя, но лучшие решения будут.
Использование umask(0777)
перед созданием файла.
Запись файла в файловой системе будет полностью недоступна [*] (т.е. права доступа ----------
), даже если дескриптор файла, который у вас есть, разрешает запись.
затем chmod()
файл, как только вы закончите:
my $file = 'foo.txt';
my $umask = umask(0777); # change the umask
open(OUT, '>', $file); # create the file
umask($umask); # reset the umask
print OUT "testing\n"; # put stuff in your file
close(OUT); # finished with that...
chmod(0644, $file); # change the permissions
NB: на самом деле это не "блокировка" в строгом смысле, когда операционная система активно запрещает доступ к файлам. Это "хак" на уровне файловой системы - если вы не можете открыть файл, он будет заблокирован.
[*] кроме как root
processe.
(FWIW, чтение наполовину записанного файла приведет к состоянию EOF.)
Либо это поддерживается в вашей операционной системе, либо нет. Если это так, то это легко и просто.
use Fcntl qw( O_CREAT O_EXCL O_WRONLY O_EXLOCK );
$creat_flags = (O_CREAT | O_EXCL | O_WRONLY | O_EXLOCK );
sysopen(SOMEHANDLE, $somepath, $creat_flags, 0666)
|| die "$0: couldn't sysopen $somepath with flags $creat_flags: $!";