Newsgroup: it.comp.os.linux.development
Titolo: File lock e threads

   Salve a tutti...
Sono incocciato in un problema credo banale, ma non riesco a venirne a
capo... Lavorando in C++ sto tentando di creare una nuova classe stream per
facilitare l'uso dell'output delle informazioni su di un file di log. In
pratica ogni sync che arriva al buffer da me creato aggiunge delle
informazioni aggiuntive alla linea scritta.
    Tutto andava bene finche` usavo un unico thread (o processo). Se,
pero`, voglio far si che piu` threads (o processi) tentino di scrivere
sullo stesso file iniziano i casini.
   L'implementazione da me scelta fa si che ogni thread possieda una copia
diversa dell'oggetto logstream. Ogni copia ha un suo buffer ma condividono
lo stream su cui effettivamente viene fatto l'output. In pratica la classe
logstreambuf contiene un oggetto ofstream che, nelle copie da un altro
oggetto logstreambuf, viene aperto a partire dal file descriptor del
precedente. (vedere [1] per dettagli)
   Il problema, a questo punto, e` che i diversi thread riescono a lockare
(flock o fcntl) il file anche contemporaneamente e ci vanno a scrivere
assieme. La soluzione banale sarebbe quella di riaprire ogni volta il file
a partire dal nome dello stesso in modo da creare un file descriptor
diverso per ogni thread: a questo punto le varie chiamate a flock
funzionerebbero nel modo corretto.
   Ho gia` provato questa soluzione e funziona, ma cosi` facendo spreco un
certo numero di descriptor quando ne basterebbe uno solo. Non voglio usare
un mutex (e quindi neanche i derivati dei vari flockfile) perche` vorrei
usare questa classe anche in programmi non threaded (che usano, presempio,
la fork). dup, oltre a non risolvere il problema, mi riproduce il problema
degli n file descriptor aperti contemporaneamente.
   In sostanza mi sento un po' "bloccato"... Possibile che non esista un
modo per lockare da due thread (o da due processi) diversi lo stesso file
descriptor senza usare un mutex (o altre soluzioni thread-specific) ??
                                           Grazie della pazienza
                                                  Rosario
[1]
class logstreambuf: public strstreambuf {
   inline logstreambuf( const logstreambuf &lsb ) : lsb_ofs( lsb.lsb_ofs.rdbuf()->fd() )
(...)
 private:
  std::ofstream     lsb_ofs;
(...)
};
-- 
                          |  
\|/ ____ \|/   \ ||_|     |  Tutti mentono; ma non importa, 
"@'/ ,. \`@"    \|| |     |  perché nessuno sta a sentire.
/_| \__/ |_\ Vax Headroom |  
   \__U_/                 |          Legge di Lieberman

Sono incocciato in un problema credo banale, ma non riesco a venirne a
ho fatto la stessa cosa in Delphi (quindi su Win)
ma il concetto è lo stesso...
La cosa + "pulita" è quella di implementare un unico thread "dedicato" alla
scrittura del file di log
SOLO lui utilizza la classe da te creata.
gli altri thread inviano i messaggi da scrivere su file di log a
quest'ultimo thread.
In questo modo "ognuno ha il suo compito", puoi scrivere una sola funzione
(chiamata
dai tutti i thread) per l'invio dei msg al thread che gestisce il file di
log ed è anche + performante...
ciao
Giorgio

 quest'ultimo thread.
[cut]
   E` un'ottima idea, tra l'altro uso un meccanismo simile per altri
scopi nel mio programma threaded... Peccato che poi una classe cosi` la
potrei usare solo all'interno di un programma threaded e questo non mi fa
piacere piu` di tanto...
   Stavo pensando anche ad un'altra possibilita`: finora i problemi
nascevano perche`, nello scrivere sul file, usavo le funzioni ad alto
livello della iostream. E se provassi ad essere piu` atomico ??? Nel senso
se, invece di usare la iostream, chiamassi la write a basso livello in
un'unica chiamata, non potrebbe funzionare lo stesso senza far intervenire
alcuna protezione ??? Del resto la write dovrebbe essere thread-safe o mi
sbaglio ???
   Se ho detto una bestialita` chiedo venia e mi cospargo il capo di
cenere... Del resto non e` da molto che metto le mani dentro codesti
argomenti...
                                             Rosario


 sbaglio ???
Sbagli. La write() non ha  alcun meccanismo di locking interno. Tornando
alla tua classe, la soluzione piu` semplice e` l'uso di un unica istanza
che effettua  le scritture con  l'uso di  una mutex per  serializzare le
scritture.
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
ATTENZIONE: il mio indirizzo email e` cambiato, quello vecchio verra` 
disabilitato a breve.
Il piu` bel momento dell'amore e` quando ci si illude che duri
per sempre; il piu` brutto, quando ci si accorge che dura
da troppo.

 sbaglio ???
E' thread safe ma non come vorresti. Nel senso che le strutture dati usate
per la write sono thread safe ma vedrai come mischia le scritture sul file.
Senza stare tanto a girarci intorno: se vuoi una scrittura "normale" su file
da piu' thread l'unica soluzione e' flockfile e magari pure fflush.
-- 
  Giuseppe "Cowo" Corbelli \/\ My software: 
http://yoda.ing.unibs.it/~cowo
	**ANTI-SPAM** -- **Substitute IHATESPAM with cowo to reply by mail**
  -<! When you say "I wrote a program that crashed Windows", people just stare
     at you blankly and say "Hey, I got those with the system, *for free*" !>-
                                (By Linus Torvalds)

sbaglio ???
vedi le risposte degli altri... evita la cenere...e qualche pippa mentale
(in senso buono ^__^) di
troppo... a volte le cose + semplici sono le migliori...soprattutto se ci
devi rimetter mano!!!!
ciao e buon lavoro
Giorgio

 scritture.
Non ho idea di come farlo in C++ con gli iostream (che conosco pochissimo), 
ma per fare un file di log in genere basta aprire il suddetto in append e 
poi scriverci (quante volte vuoi e da quanti processi/thread vuoi) con 
write. Dopo di che le cose saranno scritte atomicamente in coda (e non 
dipende da meccanismi di locking interni di write, che appunto non ci sono, 
ma da come sono realizzati i file in sistema unix).
Ciao
Simone.

 ma da come sono realizzati i file in sistema unix).
Ma  ne sei  certo? L'operazione di  scrittura non  e` mica  atomica, per
quello che ne so io.
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
ATTENZIONE: il mio indirizzo email e` cambiato, quello vecchio verra` 
disabilitato a breve.
Se il  destino di un uomo  e` annegare, anneghera` anche  in un bicchier
d'acqua.
Proverbio yddish

diversa dell'oggetto logstream.
Una soluzione che ti puo' apparire banale: hai pensato di
appendere i messaggi da scrivere ad una lista all'interno
dell'applicazione e attribuire ad un solo la thread il
compito di scrittura di questi messaggi ?  In questo modo i
diversi thread non farebbero altro che aggiungere il
messaggio in memoria, mentre un unico thread si occuperebbe
di scrivere i messaggi su disco.  A questo punto, la
questione thread-safe o meno si sposta sull'oggetto
condiviso, di memorizzazione delle linee di log, ma e' molto
piu' facile da gestire.
-- 
Andrea Laforgia - walkietalkie(at)
libero.it
"Meglio cieco che negro" (Stevie Wonder)

Scusate, non avevo letto il messaggio di Gio.
Aggiungo, comunque, che la classe che compie il log dovrebbe
essere un singleton.


 ma da come sono realizzati i file in sistema unix).
Non hai la certezza che le scritture siano sequenzializzate come vuoi. E
nemmeno hai la certezza che se vuoi scrivere una riga questa non venga
mischiata con altre prodotte da altri thread.
-- 
  Giuseppe "Cowo" Corbelli \/\ My software: 
http://yoda.ing.unibs.it/~cowo
    **ANTI-SPAM** -- **Substitute IHATESPAM with cowo to reply by mail**
  -<! *Real* programmers use cat > a.out! No way, /real/ ones
        use zcat > a.out 'cause you can type faster that way. !>-

 quello che ne so io.
Certo che non e' atomica. E' un punto di bloccaggio per i POSIX threads.
