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?

È stato utile?

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

  1. creare il file in una directory temporanea e quindi
  2. 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: $!";
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top