Newsgroup: it.comp.lang.delphi
Titolo: Ancora su Thread e buffer condiviso

Ciao a tutti,
avrei bisogno di un altro vostro gentile chiarimento.
Ricapitolando a grandi linee:
la mia piccola applicazione all'avvio crea ed inizializza un buffer di 
tipo TmemoryStream ed utilizza due TIdTCPServer.
Il buffer viene  scritto quando un TIdTCPServer riceve dei dati nella 
procedura execute del tcpserver e viene letto invece dal secondo 
TCPServer che invia una copia su richiesta ad ogni client connesso 
sempre utilizzando la procedura execute.
Il mio dubbio è , visto che ogni scrittura e lettura del buffer viene 
fatta all'interno di un thread gestito dai TCPserver (TContext)questo è 
sufficiente perchè non si verifichino letture e scritture contemporanee 
con blocco dell'applicazione oppure dovrei usare ad esempio un oggetto 
TCriticalSection con i relativi enter e leave ?
 
Grazie a tutti.

Secondo me devi chiarirti le idee..
 
1) in generale, avere due o piu' thread non e' LA SOLUZIONE per l'accesso a risorse condivise ma CORE DEL PROBLEMA dell'accesso a risorse condivise.
 
2) ad ogni evento Execute tIdTcpserver apre un thread per gestire la ricezione.
Qua dentro metti la logica per aggiornare il tuo buffer. 
 
Un errore comune di tanti e' prp mettere in questo evento del codice che usa cose esterne all'evento senza preoccuparsi di gestire gli accessi multipli:
 
*chi dice al thread se puo' scrivere il buffer o no?????*
 
Risposta: nessuno. Quindi...?
 
3) io userei 2 buffer e non uno solo
Il buffer 1 viene usato SOLO PER RICEVERE e viene usato SOLO dal socket che riceve.
Nella onExecute di RICEZIONE va il codice che aggiorna stu kaz di buffer.
Quando la scrittura del buffer e' COMPLETA, USANDO UNA CRITICAL SECTTION, si accede al buffer2 che e' quello che viene inviato ai client:
Lo blocchi, 
lo aggiorni
lo sblocchi
 
In questo modo hai meno delay e, sopratutto, durante la fase di aggiornamento di buffer1 esiste sempre un buffer2 da inviare ai client. 
AllA peggio, il client ricevera' un buffer vecchio, ma NON DOVRA ASPETTARE che il buffer sia aggiornato, senza contare che l'aggiornamento di buffer2 viene fatto in un colpo solo.
 
Ovviamente, ma non per tutti, separando le cose in questo modo potresti introdurre delle logiche in fase di ricezione del tipo "aggiorno buffer2 solo se e' cambiato".
Ovvero:
 
ricevo i dati e aggiorno buffer1
calcolo un hash o similare di buffer1
se hash del nuovo buffer1 <>  hash dell'attuale contenuto di buffer2:
A) blocco buffer2 (criticalsection), 
B) lo aggiorno, 
C) memorizzo il nuovo hash
D) lo sblocco
 
Ri-Ovviamente, ma non per tutti, quanto ho scritto va eventualmente ripensato in funzione di 2, no 3, dati che non hai fornito:
 
1) dimensione indicativa del buffer
2) frequenza indicativa di aggiornamento 
3) numero indicativo dei client connessi
 
A.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Il tuo buffer e' istanziaESTERNO ai thread usati dai TCPServer, giusto?
 
 
A.

 TCriticalSection con i relativi enter e leave ?
 
Visto il contesto parallelo con cui i client richiedono i dati, per 
evitare le race conditions è opportuno che proteggi la struttura shared 
con una critical section nel getter ma anche nel setter dei dati, in 
modo che una sola richiesta di copia alla volta venga servita e che 
evita che mentre stai copiando i dati il thread che scrive ci vada sopra 
a sporcarli.
 
Se vuoi approfondire e/o ottimizzare il tuo server vedi questo:
http://www.eonclash.com/Tutorials/Multithreading/MartinHarvey1.1/Ch9.html
 
 
 
 
-- 
morde
Android
QT 4.7
Delphi (5,6,7.. expired)
Firebird Database
 


Grazie per la risposta.
Visto che il buffer viene scritto da una sola fonte ad intervalli di un 
secondo e letto in modo random da tanti utenti ho trovato questo oggetto 
che sembra fare al caso mio:
TMultiReadExclusiveWriteSynchronizer
si crea un istanza a livello globale e poi si utilizza BeginWrite ed 
EndWrite per la scrittura e BeginRead ed EndRead per la lettura.
Sai se esistono controindicazioni o problemi conosciuti ?
 

 Sai se esistono controindicazioni o problemi conosciuti ?
TMultiReadExclusiveWriteSynchronizer non lo conosco, mi sono documentato 
qui: 
http://edn.embarcadero.com/article/28258
 
 
Mi sembra vada bene per te: l'importante è che mantieni l'architettura 
del producer-consumer, cioè *un solo thread produce*, tanti consumano e 
tutti si sincronizzano con i semafori.
 
Nell'articolo si mette in guardia del pericolo di deadlock nel caso di 
lettura/scrittura ad opera dello stesso thread, ma come già ti ho doetto 
sopra se tu tieni separati il producer (writer only) dal consumer 
(reader only) sei ok.


 (reader only) sei ok.
 
A proposito, ho trovato questo link dove si può scaricare un ebook "for 
free" sul tema dei semafori.Per chi vuole approfondire.
http://greenteapress.com/semaphores/
 


 free" sul tema dei semafori.Per chi vuole approfondire.
 
Cosa c'e' da approfondire?
Se e' giallo, accelleri per passare prima che diventa rosso
Se e' verde,  accelleri per passare prima che diventa giallo
Se e' rosso, si decide in base al contesto e al momento...
 
:-D

 :-D
 
Ma non era "se e' verde, rallenti per non essere tamponato da quello che passa con il rosso" ? :)
 
Giacomo
 
 

 Se e' rosso, si decide in base al contesto e al momento...
 
LOL dove hai studiato per prendere la patente? Io quando entro nell'area 
di un semaforo verde, rallento e mi fermo, scendo, mi faccio un caffè, 
risalgo e riparto prima che diventi rosso.. :P


> Ma non era "se e' verde, rallenti per non essere tamponato da quello che passa con il rosso" ? :)
 
 
..in realta, accelleri per superare il semaforo.
Poi, rallenti per vedere se qualcuno passa col rosso.
 
:-D

 risalgo e riparto prima che diventi rosso.. :P
 
Allora hai culo per 2 motivi...
 
1) il verde non dura 10 millisecondi
2) trovi sempre il parcheggio...
 
Come mi incazzo quando in coda davanti ad un semaforo col verde che dura 10 millisecondi ti tocca aspettare xche quelli davanti si intalleano...
 
 
A.


 
Grazie mille.