C'è un modo per creare un file bloccato nel punto della creazione, a Perl?
-
29-10-2019 - |
Domanda
Devo creare un file bloccato contro le letture, nel punto della creazione, in modo che altri processi che potrebbero andare alla ricerca di questo file non iniziano a leggerlo, prima che sia stato completamente scritto.
So che posso creare e poi Bloccalo, ma sono preoccupato che questo mi lasci aperto a una condizione di gara.
O Non mi preoccupo di niente qui? Se ho un file aperto per la scrittura e quindi aprilo per la lettura con un altro processo, il processo di lettura non vedrà mai un EOF fino a quando il processo di scrittura chiuderà il file?
Soluzione
C'è una condizione di gara con >
e >>
, ma può essere aggirato 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 $!;
...
C'è anche una condizione di gara nello scenario che descrivi.
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 strategia comune per evitare questo problema è avere lo scrittore
- creare il file in una directory temporanea e quindi
rename
Il file nella directory il lettore monitora al termine del file.
rename
è un'azione atomica, quindi il file apparirà completamente formato nella directory i monitor del lettore. Ciò richiede la cooperazione dello scrittore, ma le migliori soluzioni lo faranno.
Altri suggerimenti
Uso umask(0777)
Prima di creare il file.
La voce del file nel file system sarà completamente inaccessibile [*] (cioè le autorizzazioni ----------
), anche se il manico del file che hai ancora permessi.
Quindi chmod()
il file una volta terminato:
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: Ciò non è in realtà "bloccarsi" nel senso rigoroso, in cui il sistema operativo impedisce attivamente l'accesso ai file. Questo è un livello di system di file "hack"-se non puoi effettivamente aprire il file, è un po 'bloccato.
*] tranne root
processo.
(FWIW, leggendo un file a metà scritta volere provocare una condizione EOF.)
O questo è supportato sul tuo sistema operativo, oppure non lo è. Se se ciò, è facile e semplice.
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: $!";