¿Hay alguna manera de crear un archivo bloqueado en el punto de creación, en Perl?

StackOverflow https://stackoverflow.com/questions/6387334

  •  29-10-2019
  •  | 
  •  

Pregunta

Necesito crear un archivo que esté bloqueado contra las lecturas, en el punto de la creación, para que otros procesos que puedan ir a buscar este archivo no comiencen a leerlo, antes de que se haya escrito por completo.

Sé que puedo crear y después Bloqueo, pero me preocupa que esto me deje abierto a una condición de carrera.

O ¿Me estoy preocupando por nada aquí? Si tengo un archivo abierto para escribir y luego abrirlo para leer con otro proceso, ¿el proceso de lectura nunca verá un EOF hasta que el proceso de escritura cierre el archivo?

¿Fue útil?

Solución

Hay una condición de carrera con > y >>, pero se puede evitar usando +<.

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

También hay una condición de carrera en el escenario que describe.

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

Una estrategia común para evitar este problema es tener al escritor

  1. Crear el archivo en un directorio temporal y luego
  2. rename el archivo en el directorio que el lector monitorea cuando el archivo está completo.

rename es una acción atómica, por lo que el archivo aparecerá completamente formado en el directorio que el lector monitorea. Esto requiere la cooperación del escritor, pero las mejores soluciones lo harán.

Otros consejos

Usar umask(0777) antes de crear el archivo.

La entrada del archivo en el sistema de archivos será completamente inaccesible [*] (es decir, permisos ----------), a pesar de que el manejo del archivo aún tiene permisos.

Después chmod() el archivo una vez que haya terminado:

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: Esto en realidad no está "bloqueando" en el sentido estricto, donde el sistema operativo evita activamente el acceso a los archivos. Este es un "pirateo" de nivel de sistema de archivos: si realmente no puede abrir el archivo, entonces está algo bloqueado.

*] excepto a root Processe.

(FWIW, leyendo un archivo a medias escrita voluntad dar como resultado una condición EOF).

O esto es compatible con su sistema operativo, o no lo es. Si es así, es fácil y simple.

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: $!";
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top