Есть ли способ создать файл, который заблокирован в момент создания, в Perl? - PullRequest
4 голосов
/ 17 июня 2011

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

Я знаю, что могу создать и затем заблокировать его, но я обеспокоен тем, что это оставляет меня открытым для состояния гонки.

Или Я здесь ни о чем не беспокоюсь? Если у меня есть файл, открытый для записи и затем открывающий его для чтения другим процессом, будет ли процесс чтения никогда не видеть EOF, пока процесс записи не закроет файл?

Ответы [ 3 ]

8 голосов
/ 17 июня 2011

Существует условие гонки с > и >>, но его можно обойти, используя +<.

# >
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

Распространенная стратегия, позволяющая избежать этой проблемы, заключается в том, чтобы писатель

  1. создал файл во временном каталоге, а затем
  2. rename файл вкаталог, который читатель отслеживает, когда файл завершен.

rename является атомарным действием, поэтому файл будет полностью сформирован в каталоге, который отслеживает читатель.Это требует сотрудничества писателя, но лучшие решения будут.

8 голосов
/ 17 июня 2011

Используйте 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

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

[*] кроме root обработки.

(FWIW, чтение наполовину записанного файла приведет к возникновению условия EOF.)

3 голосов
/ 17 июня 2011

Либо это поддерживается в вашей операционной системе, либо нет.Если это так, то это легко и просто.

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: $!";
...