Newsgroup: it.comp.java
Titolo: Sincronizzare N threads in scrittura file condiviso

Salve.
Devo sincronizzare N threads affinch� ognuno di essi
scriva correttamente in un unico file (condiviso).
Ciascun thread legge da un file(in sola lettura),
elabora i dati letti, e scrive una singola riga di testo
in un file(una sorta di 'resoconto finale' o 'rapporto')
che � condiviso tra tutti gli N threads.
- N threads : N files distinti in sola lettura (input)
  -> N righe nel rapporto
- 1 file testuale in sola scrittura (output) , il rapporto.
Ho provato con wait(), notify(), blocchi e/o metodi synchronized...
ma il *numero di righe* nel rapporto � sempre dipendente
dalla particolare esecuzione,  per cui a volte trovo tutti gli N risultati,
come deve essere, altre volte trovo  n<N  risultati nel Rapporto
(cio� n<N  linee di testo) (nota: ogni linea testuale elaborata
da un thread � diversa da tutte le altre).
Non c'� determinismo insomma.
E' come se qualche thread non scrivesse in bel niente nel file.
Capita anche, di rado, di vedere sequenze impreviste
di caratteri 'spazio' a fine riga.
Ho provato svariate 'soluzioni', ma non ho ancora risolto il problema.
Senza modalit� multithread(che � opzionale) � tutto ok.
Come posso risolvere secondo voi ?
Grazie per l'attenzione.
A presto!
F.

 Come posso risolvere secondo voi ?
Io avrei delegato la scrittura nel file di output ad un oggetto che 
scoda le righe di testo una alla volta da un BlockingDeque, tutte le 
altre thread accodano le loro righe al BlockingDeque invece di scrivere 
direttamente nel file.

"Dr.Ugo Gagliardelli" <do.no...@me.please> ha scritto nel messaggio 
news:j0pi4d$grl$1...@speranza.aioe.org...

Mmmm....idea interessante e soluzione elegante.
Non sarï¿œ computazionalmente troppo dispendiosa?
Peccato che purtroppo io non l'abbia mai vista implementata...
Se ho ben capito lo schema ï¿œ cosï¿œ :
1. il thread generico non scrive direttamente:
    la sua richiesta si mette in coda per la scrittura;
2. l'oggetto che gestisce la coda esegue la scrittura
    per la generica richiesta accodata e infine la 'scoda'.
Mi sapresti dire come mai con wait, notify, synchronized  non funziona?
Qualche schemino piï¿œ rapido e semplice esiste?
Grazie e a presto!
F.

 Qualche schemino piï¿œ rapido e semplice esiste?
Piu' rapido di cosi'? La thread che scoda la si fa con qualche riga di 
codice, il metodo di accodamento delle thread multiple si semplifica di 
molto rispetto al metodo che adesso si deve aprire il file scrivere la 
sua riga e richiudere il file; ed inoltre non ti devi gestire le 
eventuali concorrenze sul file stesso, e' facile che aprendo un file in 
scrittura il sistema operativo metta a sua volta dei lock.

 sistema operativo metta a sua volta dei lock.
Ok ...
Grazie per l'attenzione.
Saluti.
F. 

 N threads nell'accesso in sola scrittura ad un unico file condiviso.
Utilizzare wait, notify e synchronize e' comunque un metodo prono a 
blocchi ed errori di vario tipo.
Probabilmente sarebbe il caso di utilizzare un Semaphore creato fair (in 
modo che l'accesso segua l'ordine con cui viene richiesto) con un solo 
permesso, ed utilizzarlo prima di scrivere. Ad esempio:
final Semaphore writesem = new Semaphore(1, true);
Thread nthread = new Tread(new Runnable() {
   public void run() {
      Semaphore sem = writesem;
      boolean acquired = false;
      while(!Thread.currentThread().isInterrupted()) {
         try {
           acquired = false;
           sem.acquire();
           acquired = true;
           .... scrivi file
         } catch(Exception e) {
           ...
         } finally {
           if (acquired)
             sem.release();
         }
      }
   }
});
Il metodo acquire() acquisisce un permesso se disponibile 
immediatamente, altrimenti aspetta.
Il meodo release() restituisce il permesso, ovvero aggiunge un permesso 
al pool di permessi del semaforo. Poiche' si vuole un solo accesso 
concorrente, ho condizionato release() al fatto che il permesso sia 
effettivamente stato acquisito, onde evitare che i permessi aumentino 
oltre a quello strettamente necessario.
Questo metodo non evita comunque gli evetuali lock del sistema operativo 
legato all'accesso condiviso in scrittura: alcuni sistemi operativi si 
comportano in un modo e altri in altro modo. E la JVM non puo' decidere 
strategie diverse di allocazione se l'os non lo permette.

 strategie diverse di allocazione se l'os non lo permette.
Infatti alla fine ho risolto nel modo che cercavo:
synchronized(output_file) {
    while(!libero) {
     try {
      output_file.wait();
     } catch (InterruptedException ie)  { ie.printStackTrace(); }
    }
    libero=false;
    << qui 2 righe per scrivere una stringa S(giï¿œ pronta prima)
    nel file condiviso ... ma anche una sola riga>>
    libero=true;
    output_file.notify();
}
Passando il file al costruttore di ogni thread, tutto va benone.
Il boolean 'libero'  viene inizializzato a true dal costruttore.
Nï¿œ 'libero' nï¿œ 'output_file' necessitano di essere 'static'
(io pensavo di si ... ).
Il mio errore era sulla risorsa da sincronizzare, mi sa...
(cioï¿œ il file di output, l'unica risorsa veramente condivisa,
dunque da sincronizzare)
Ti ringrazio per l'attenzione e per le spiegazioni che hai voluto fornirmi.
Buona giornata.
F.

 }
Ecco vedi, notify() notifica tutti i thread in attesa, per cui puo' 
essere che piu' di un thread escano dal wait() contemporaneamente.
Questo e' un aspetto abbastanza subdolo di cui e' abbastanza complicato 
tenere conto.
La classe java.util.concurrent.Semaphore invece, tiene conto di questo 
aspetto.

 essere che piu' di un thread escano dal wait() contemporaneamente.
Scusa, ho detto una cazzata, confondevo con notifyAll(), comunque non 
hai la certezza di quale thread si svegliera' dal wait().


Infatti, sono tutti thread indipendenti e legittimamente concorrenti.
Non debbo avere alcuna certezza sull'ordine di scrittura.
La certezza che voglio ï¿œ che ogni thread scriva *indisturbato*
la sua stringa(generata nel proprio spazio) nel file condiviso
in sola scrittura. Il semaforo sarebbe stato equivalente.
Ciao ciao.
F.