Newsgroup: it.comp.lang.delphi
Titolo: Buffer in comune

Ciao ,
avrei la necessità di creare con Delphi 2010 un buffer in memoria dove da un 
lato ogni secondo viene "riempito" da un'immagine e dall'altro
venga letto a richiesta ed in modo random da più thread.
Potete per favore darmi due dritte su quale possa essere il metodo migliore 
per realizzare questo tipo di buffer ?
 
Grazie a tutti.
 
 


Sinceramente puoi fare come ti pare a patto che semafori l'ingresso 
delle procedure di lettura/scrittura in maniera da non avere conflitti 
tipo cosi'
 
Dichiara una variabile globale tipo:
 
Semaforo_sul_rosso : Boolean;
 
che ovviamente va inizializzata a FALSE. Ora in testa alle procedure che 
devi semaforare usa una cosa tipo:
 
Begin
   // Attesa semaforo verde
   While Semaforo_Sul_Rosso do Application.ProcessMessages;
 
   // Blocco semaforo
   Semaforo_Sul_Rosso := True;
 
   {...
   Qui' il codice della tua procedura che si occupa
   della lettura/scrittura
   ...}
 
   // Sblocco semaforo
   Semaforo_Sul_Rosso := False;
 
   {...
   Qui' puoi manipolare gli eventuali dati
   ...}
End;

 cosi'
 
 
Perfetto !
Infatti i miei problemi derivavano da alcuni conflitti lettura/scrittura...
Grazie mille. 
 
 

 venga letto a richiesta ed in modo random da più thread.
 
Non so se esista anche in D2010, ma sembra che
TMultiReadExclusiveWriteSynchronizer (help: TThread -> see also) sia
quel che cerchi.
 
Saluti
Paolo Arosio

 ha scritto nel messaggio 
news:BvMYq.133126$GZ3....@tornado.fastwebnet.it...

Giuseppe:
Ho letto che hai risolto. Ti suggerisco comunque un modo, magari lo puoi 
usare in futuro per evitare di creare variabili globali e comunque lasciare 
che se ne occupi Windows di semaforizzarti l'accesso ad aree o dati comuni.
 
Nella tua main form, o in un componente per la gestione di dati comuni, 
dichiari una variabile semaforo.
FLock: TRTLCriticalSection;
 
Nel costruttore della main form, o del componente, inizializzi la variabile.
InitializeCriticalSection(FLock);
 
Nel distruttore della main form, o del componente, la elimini.
DeleteCriticalSection(FLock);
 
In ogni parte di codice dove hai bisogno di leggere aree comuni a più 
threads,
prima della lettura/scrittura usi:
EnterCriticalSection(FLock);
 
Subito dopo la lettura/scrittura usi:
LeaveCriticalSection(FLock);
 
Attenzione: entrando in criticalsection devi assolutamente evitare di usare 
funzioni che fanno uso della stessa criticalsection istanziata, altrimenti 
blocchi tutto. Per questo motivo ti suggerisco di usare enter e leave subito 
prima e subito dopo la lettura/scrittura, e non all'inizio o alla fine di 
una procedura o una funzione, a meno che queste non abbiano soltanto le 
istruzioni essenziali per la lettura/scrittura. Altresì ti suggerisco di 
predisporre metodi comuni per la lettura e scrittura dei dati, che siano più 
vicini possibile ai dati, ossia nello stesso componente dove i dati vengono 
letti/scritti.
Nota: puoi istanziare più criticalsection.
Nota2: usando questo che ti suggerisco ti leghi alla piattaforma windows.
 
Ciao
 

 ....
 
Grazie per la risposta dettagliata,
non conoscevo questo TRTLCriticalSection, mi sembra un'ottima soluzione,
farò due prove.
Visto la tua disponibilità vorrei chiederti un'ulteriore consiglio:
per rendere disponibile ai client l'immagine che a cadenza fissa (1 secondo) 
verrà aggiornata, avevo pensato
di creare all'avvio dell'applicazione una zona di memoria globale 
(accessibile da tutti i thread, uno in scrittura molti in lettura) dove 
memorizzare l'immagine .
Questa verrà periodicamente aggiornata durante tutta la vita 
dell'applicazione e poi distrutta solo alla chiusura .
E' corretto oppure esiste qualcosa di più elegante ed affidabile ?
Volevo evitare la lettura /scrittura di un file per questioni di prestazioni 
visto che l'immagine verrà ricevuta tramite un IdTCPServer e ritrasmessa da 
un secondo IdTCPServer.
Grazie ancora.
Ciao. 
 
 

 memorizzare l'immagine .[cut]
 
Giuseppe:
Boh, in specifico sei tu ad avere il polso del tuo software e sapere cosa 
vuoi ottenere. :-)
 
Se il thread in scrittura (unico) ha una vita propria ok, ma se 
all'aggiornamento dell'immagine è comunque delegato il thread principale, ti 
conviene imho evitare di mettere in un thread l'immagine.
Sia nell'uno o nell'altro caso, farei un componente che gestisse il cambio 
di immagine. Tale componente esporrebbe un metodo per leggere l'immagine 
(coi semafori precedenti). Il componente dovrebbe essere condiviso da tutti 
gli oggetti thread che leggeranno l'immagine, e in un certo senso, per 
evitare variabili globali, la condivisione dovrebbe essere reciproca.
Nel caso di thread, il componente avrebbe vita propria e gestirebbe il 
cambio di immagine. Nell'altro caso esporrei un altro metodo per scrivere 
l'immagine (usando sempre i semafori).
Dopo la scrittura dell'immagine come farei a notificare il cambio a tutti 
gli altri componenti-thread? Ci sono due modi:
1. un polling ripetuto dei threads, ma è brutto, perché li opprimerebbe 
troppo e sarebbero costretti a fare solo quello, o quasi... e poi questa 
soluzione opprime anche la mia idea di programmazione :-D
2. il componente si occupa di notificare il cambio a tutti i thread in 
ascolto, più elegante.
Prendo la seconda strada, quella che preferisco. Come farei? Ci sono due 
modi:
1. il componente-thread mantiene una lista di threads in ascolto. i threadd 
in ascolto nel costruttore aggiungono la propria procedura evento all'elenco 
e nel distruttore la rimuovono. Dopo il cambio di immagine, il 
componente-thread si preoccupa di notificare l'evento-cambio immagine a 
tutti i threads presenti nella lista. (è sì elegante, ma è anche un minimo 
bloccante, soprattutto se ogni thread ad ogni notifica compie altre 
operazioni, oltre a quella semplice di sapere che l'immagine è cambiata)
2. il componente-thread, dopo il cambio di immagine, notifica a tutti i 
threads dell'applicazione questa nuova condizione, mediante un messaggio. 
Ricordi la lista contenitore di prima? Invece di contenere procedure evento, 
conterrà oggetti thread in ascolto, oppure solo i thread-id dei tuoi thread 
in ascolto. Userai PostThreadMessage (cerca in msdn o nell'sdk win), e 
notificherai il cambio di immagine a tutti i threads in un istante. Nei 
thread in ascolto ti preoccuperai di gestire la coda di messaggi (attivando 
la coda, cerca sempre in win32). Questo secondo me è molto elegante e non è 
bloccante, perché ogni threads gestirà nel modo più opportuno il cambio di 
immagine, nei suoi modi e tempi.
Ovviamente ogni soluzione ha la sua complessità, ma dopo averle sviluppate 
ti accorgerai che sono due sciocchezze in croce. Ci sono molte altre 
varianti, ma sta a te scegliere quella che più si adatta al tuo software. Se 
hai in progetto di portare il tuo software su altre piattaforme, scarta la 
soluzione che si lega troppo a Windows.
Spero di esserti stato utile.
Ciao!
 
Giuseppe
 

 Spero di esserti stato utile.
 
 
Sei stato molto preciso e mi hai fornito  idee utilissime,
non so come ringraziarti.
 
Ciao e nuovamente grazie
 
Beppe