Newsgroup: it.comp.lang.perl
Titolo: lock di file per la scrittura

Vorrei sapere come si fa a bloccare la scrittura su un file .txt, in modo
che mentre io scrivo su di esso non sia possibile a qualcun altro fare lo
stesso.
Possibilmente con un esempio.
(sistema op. UNIX)
Grazie.
Nicola


Premessa: il lock dei file funziona SE E SOLO SE chiunque accede al file lo
          fa usando il medesimo meccanismo di lock.
          Altrimenti non c'e' alcun locking.
	  In pratica il lock funziona solo se ad accedere al file sono
	  versioni concorrenti del medesimo programma o programmi scritti
	  per lavorare in collaborazione.
 
Soluzione
 use Fcntl qw(:flock);
 
 open (FH,'>pippo.txt') or die "Non posso aprire pippo.txt: $!";
 flock(FH,LOCK_EX);
 
 ......
 
 close(FH);
 
Non c'e' bisogno di rilasciare esplicitamente il lock, perche' viene
rilasciato alla chiusura del filehandle.
Tra parentesi, questo e' quello che c'e' scritto nella Perl FAQ.
Maurizio
-- 
Maurizio M. Munafo' / 
mmmu...@tuttocitta.it
 
"Consider Phlebas, who was once handsome and tall as you" (T.S.Eliot)

mmmu...@tuttocitta.it
 wrote:
 
 > open (FH,'>pippo.txt') or die "Non posso aprire pippo.txt: $!";
 > flock(FH,LOCK_EX);
Non mi convine affatto. Tra queste due istruzioni c'e` spazio per una
race condition: un altro programma potrebbe aprire il file. Come minimo
bisogna controllare cosa ritorna flock().
-- 
ciao, | [Per rispondere togli "toglimi" dal mio indirizzo.]
Marco | * The Internet is full. Go away.  -- Joel Furr *

 bisogna controllare cosa ritorna flock().
Hai ragione. Imperdonabile.
In realta' l'esempio tipo mostra un doppio if: prima si prova a
lockare il file in modo esclusivo ma non bloccante, poi, se non si riesce a
lockarlo, si avverte l'utente di aspettare e lo si locka in modo esclusivo
con un eventuale messaggio di errore se fallisce.
In ogni caso, non vedo dove sia possibile la race condition: se qualcun'altro
apre il file o lo ha gia' aperto, io mi blocco sul flock.
Il flock, spero, dovrebbe essere atomico.
E' certo, comunque, che sconsigliano di usare il flock su file system con
NFS dove non e' garantito il funzionamento.



Sig. Munafo',
grazie per la risposta.
Le volevo anche chiedere se esiste un modo per testare flock sul proprio
sistema.
Io ho provato scrivendo il seguente script cgi:
open(REG,">>lock.txt") or die "Non posso aprire il file";
flock(REG, 2) or die "can't flock" ;
print REG ("sto scrivendo\n\n");
open(REG2,">>lock.txt") or die "Non posso aprire il file";
print REG2 ("sto scrivendo di nuovo\n\n");
cioè in pratica senza chiudere il file dopo la prima apertura (in modo
da
lasciare attivo il lock) e provando a scrivere con un secondo
filehandle, ma mi
sembra che non considera il lock perché scrive lo stesso sul file.
Grazie.
Nicola Bonechi

 sembra che non considera il lock perché scrive lo stesso sul file.
La tua seconda operazione NON sta usando il lock. 
Il lock funziona se tutti quelli che usano il file passano attraverso la 
sequenza open, flock, usa, close.
Di solito il lock andrebbe testato facendo eseguire in parallelo lo stesso
programma (da due shell o due finestre diverse) e verificando che il secondo
si blocca...
Prova questo
 use Fcntl qw(:flock);
 open(REG,">>lock.txt") or die "Non posso aprire il file";
 unless ( flock(REG, LOCK_EX|LOCK_NB))
   {
     warn "File lockato" ;
     unless (flock(REG,LOCK_EX))
      { 
        die "Cannot lock file";
      }
   }
 print REG ("sto scrivendo $$ \n\n");
 sleep(10);
 print REG "meno 10 $$\n";
 sleep(10);
 print REG "Finito $$\n\n";
 close(REG);
Se lo esegui due volte, entro 20 secondi, da due finestre separate,
ottieni che la seconda volta ti appare un messaggio di warning (sullo
standard error) che ti dice che "File lockato at 
lock.pl
 line 5".
Puoi anche mandarlo parecchie volte in background e verificare che le
scritture sono sequenziate. 
ATTENZIONE
Nel tuo esempio, comunque, NON BISOGNA assolutamente mettere un flock(REG2,2) 
tra la open(REG2...) e la print REG2.
Il programma va in deadlock, perche' si ferma ad aspettare che sia rilasciato
il lock di REG, cosa che non puo' piu' accadere, appunto perche' il
programma stesso e' bloccato.



Ho provato ad eseguire il tuo esempio lanciando consecutivamente lo script da due
finestre di Netscape e, in effetti, la seconda finestra mi dà 505 Internal Server
Error, però se poi vado a vedere cosa c'è nel file lock.txt trovo che ha scritto
entrambe le volte, cioè il contenuto del file è questo:
sto scrivendo 13119
meno 10 13119
Finito 13119
sto scrivendo 13122
meno 10 13122
Finito 13122
Questo vuol dire che il sistema non supporta flock?
(C'è anche qualche altro sistema per lockare i file?)
Grazie.
Nicola Bonechi

 sto scrivendo 13122


1. Se il sistema non supporta flock, Perl non esegue lo script.
2. Perche' eseguire uno script non CGI da Netscape? Ovvio che il server da 
   messaggi 505: io ho scritto direttamente sul'output senza mandare header!
   Nel mio messaggio avevo parlato di esecuzione dalla linea di comando.
 
3. Il risultato che hai ottenuto e' corretto: il secondo processo CGI ha 
   emesso il warning di lock ( e quindi mandato la pagina di errore a
   Netscape), ma ha terminato l'esecuzione non appena il lock e'
   stato rilasciato.
   Infatti nel tuo file lock.txt ha la stampa, seriale, fatta dai due processi.


nico...@prof.it
 wrote:
 >cioč in pratica senza chiudere il file dopo la prima apertura (in modo
 >da
 >lasciare attivo il lock) e provando a scrivere con un secondo
 >filehandle, ma mi
 >sembra che non considera il lock perché scrive lo stesso sul file.
Flock e` un advisory lock e non un mandatory lock, funziona solo se
entrambe i programmi collaborano e usano flock.



Ho eseguito lo script via Telnet come mi avevi suggerito ed in effetti ora funziona (la
seconda esecuzione dà il messaggio di "file lockato").
Ti volevo anche chiedere (scusa per tutte queste domande ma è importante per il
programma che sto scrivendo):
devo anche inserire l'istruzione seek(REG,0,2) dopo flock per fare in modo che
l'eventuale programma concorrente in attesa legga le modifiche apportate dal primo?
Ho visto che il manuale di perl 5 la mette.
Forse perché altrimenti Il secondo script che è in attesa dell'unlock non trova ciò che
ha scritto il primo script, che dunque andrebbe perso?
Un'ultima cosa:
usare flock(REG, LOCK_EX) o flock(REG, 2) è la stessa cosa?
Grazie.
Nicola Bonechi

 usare flock(REG, LOCK_EX) o flock(REG, 2) è la stessa cosa?
E' la stessa cosa. 
Per usare LOCK_EX devi caricare il modulo Fcntl, pero' capisci subito che
tipo di lock richiedi ed e' piu' facile combinare piu' lock, specialmente se
vuoi usare LOCK_NB.
In un caso metti LOCK_EX|LOCK_NB, nell'altro devi ricordarti che per quella 
combinazione devi indicare 6.
Diciamo che e' con LOCK_EX il codice puo' essere piu' semplice da manutenere.



Mi spiace di continuare a sottoporti nuove domande ma mi sono sorti
nuovi dubbi riguardo
all'uso di flock.
Sul newsgroup comp.perl.lang.misc ho letto di uno che usava flock per
scrivere su un file
ma il suo file txt in certi casi risultava troncato.
Secondo lui un motivo poteva essere che il sysadmin avesse eseguito un
kill -9 mentre lo
script stava scrivendo sul file.
C'č un modo per evitare questo problema? (tipo annullare le modifiche se
lo script non si completa, 
p.es
. in caso di interruzione della
connessione client-server durante la scrittura).
Nel caso uno script apra e chiuda piů volte il file con flock,
l'istruzione use Fcntl
qw(:flock); va messa ogni volta prima di open() oppure basta metterla
all'inizio del
file?
L'istruzione seek(FILEHANDLE,0,2) dopo flock č necessaria anche se leggo
il file riga per
riga con while (<FILEHANDLE>) ?
Per eliminare questo problema di scrittura contemporanea non č forse
meglio mettere
un'istruzione del tipo:
   if (file č lockato)
   {
   print "File attualmente in uso. Riprova";
   exit;
   }
Nel caso come andrebbe scritta la condizione?
Spero di non assillarti piů con questo problema.
Grazie.
Nicola Bonechi

entrambe i programmi collaborano e usano flock.
Scusa, cosa intendi per "collaborano"?
Ciao
Andrea



Che sono stati scritti tenendo in mente che i file possono essere usati da
altri e quindi usano sempre il meccanismo di flock quando li aprono.
I lock sono come un semaforo ad un incrocio... tu puoi fermarti con il rosso 
ma nessuno ti vieta di passare dritto fregandotene delle luci: il risultato
e' un possibile schianto.
I semafori, appunto, sono efficaci perche' la gente li rispetta e si ferma
se c'e' la luce rossa.


se c'e' la luce rossa.
Chiarissimo, anche se, purtroppo, per il semaforo non č sempre vero.
Grazie
Andrea