Newsgroup: it.comp.lang.delphi
Titolo: TThread e Synchornize

Ciao,
Ho dovuto per questioni di velocità implementare dei thread all'interno di
un programma già finito, premetto questo per dire che non ho potuto cambiare
radicalmente la struttura a mio piacimento.
Il mio thread fa una serie di lavori ed aggiorna degli oggetti sul form,
siccome gli aggiornamenti sono cambi di una stringgrid vorrei usare il
synchornize in modo da evitare inconvenienti.
Il problema è che il Synchornize vuole come parametro una procedura senza
parametri.
Io ho un sacco di righe di codice (discontinue cioè che non posso
raggruppare in una singola procedura) del tipo:
form.myGrid.Cell[x,y] := RS.fieldbyname('pluto').AsString;
etc etc
ora non potendo fare una cosa del tipo Synchronize ( form.myGrid. cell etc
etc )
cosa devo fare ?????  mi devo scrivere 50 procedure da una linea l'una e poi
richiamarle con il Synchornize ????
Non esiste un altro modo + agevole ?
grazie a tutti
Ciao
Alberto


 ABLS Team (
www.abls.it
)

 principale dell'applicazione.
no, è proprio questo il problema, se metto tutto in Synchronize il form mi
si blocca in attesa che finisca il mio thread ed è proprio questo che non
voglio, nel thread ci sono un sacco di query e calcoli lenti che devono
funzionare necessariamente in background, per fare questo ho bisogno di usar
eil synchronize SOLO sulle istruzioni che accedono alle risorse condivise
sul form, il problema è che le istruzioni sono molte e se per ognuna di
queste devo fare una procedura senza parametri per poi chiamarla col
Synchronize è un macello nel sneso che devo smembrare il codice ed otlre a
diventare poco chiaro diventa anche poco performante, ovviamente se non ho
altre possibilità farò cosi.
Come accennato in precedenza in origine questo programma non usava i thread
e quindi era strutturato in modo differente.
Per spiegarmi meglio:
sul FORM principale c'e' una StringGrid, ogni cella della stringgrid è il
risultato di una query del tipo SELECT SUM(campo) FROM bla<hblah .....
Siccome la StringGrid è generata in modo dinamico ( numero colonne, righe,
etc etc variano a seconda di un risultato di una query precedente ) ho
pensato di mettere in un thread la generazione della griglia e anche il suo
riempimento.
Ovviamente il problema sta nel fatto che l'execute del thread non è
immediato :
procedure myTHR.execute();
begin
    try
       MyProcedure; // NOT Synchronized !!!
       Terminate;
    except
      Abort;
   end;
end;
procedure myTHR.MyProcedure();
begin
       For i := 1 to MyVAr do
        begin
                blah blah
                query1
                form.grid.cell[x,y] := RS.fieldbyname('blah').asString;   //
questa andrebbe Synchronized !!!!!!!!!
                query2 etc etc
                etc etc
        end;
end;
Come avrai capito c'e' un doppio problema :
1 - Sincronizzare tutto il codice che va ad agire sulle risorse condivise
del FORM
2 - La distruzione del thread !!!!!
L'utente può terminare il Form o richiedere un altra interrogazione delle
tabella in modo tale da generare un nuovo thread, questo significa che il
thread precedente deve essere terminato, ma cosi come è strutturato il
codice il thread termina solo quando MyProcedure termina !!!
In ogni caso ho risolto il problema chiamando (myTHR).Terminate  ed
aggiungendo nel codice un controllo del tipo
if terminated then exit;
Questo risolve alcuni problemi  ma IN OGNI CASO non mi garantisce la
gestione corretta degli errori!!!!
COSA POSSO FARE ???
Mettere il controllo [if terminated then exit] su ogni istruzione ???  un
disastro !!!!
Se avete qualche idea, suggerimento correzione anche drastica  è ben accetta
!!!!
Con i controllli che ho fatto il programma funziona ma ogni tanto v ain
errore, anche se capita raramente non mi piace per niente il modo in cui
l'ho implementato.
Ho letto che qualcuno di voi usa una specie di variabile semaforo, in questo
caso come si potrebbe applicare ??
per ora vi ringrazio tutti :-)
ciao
Alberto

Potresti provare con il messaggio WM_SETTEXT e la postmessage senza usare la
Synchronize
CIAOUX


Credo che l'uso del Terminated sia un buon metodo per identificare quando il
programma principale ha decretato che il thread debba terminare. Se vuoi
controllare l'evento di annullamento dell'operazione, credo che sia
necessario testare il valore della proprietà Terminated ad ogni ciclo (non è
d'obbligo inserire il test dopo ogni singola istruzione).
Il semaforo che hai citato fa probabilmente è la Critical Section oppure il
Mutex, ma non so se possono essere utili per risolvere il tuo problema.


 d'obbligo inserire il test dopo ogni singola istruzione).
infatti è quello che faccio ma anche questo controllo non rende del tutto
sicuro il codice
per chè se mi trovo in questa situazione :
for i:=1 to N
    begin
            if Terminated exit;
            istruzione1
            istruzione 2
            istruzione 3  (  tempo di esecuzione 1 secondo )
            istr 4
            istr N
    end;
Come puoi capire se l'istruzione 3 impiega per esempio 1 secondo per essere
eseguita, può accadere che nello stesso istante il form chiami la terminate,
ma siccome prima di eseguire la istr3 la var booleana terminated era false
esegue anche l'istruzione 4 che se interascisce con la risorsa condivisa può
causare senz'altro un errore, perchè finchè il ciclo non termina con
l'istruzione N non ho nessun controllo e quindi il codice è in una
condizione NON-sicura.
Ovvio che una situazione del genere non capiterà di sovente ma,
ciononostante può capitare, e, seguendo la legge di Murphy, capiterà proprio
nel momento peggiore :-) Inoltre non è indice di una buona programamzione
:-(((
Si può mettere una toppa del tipo Sleep(1000) prima di distruggere le
risorse condivise, ma anche qui, stiamo parlando di toppe :-)
grazie ancora
ciao!

  [...]

Innanzitutto, devi mettere una Sleep, anche con tempo '0', nel thread
separato, in modo da cedere il controllo al sistema operativo e dare una
maggiore possibilità a tutti gli altri thread attivi nel sistema di eseguire
le proprie routine, senza necessariamente impegnare tutto il "time slice"
concesso.
In secondo luogo, non capisco come fai a determinare che l'applicazione si
trovi in una condizione "NON sicura" nel caso che hai riportato. Se il form
principale esegue la Terminate del thread, verrà completato il ciclo delle
istruzioni e l'interruzione del thread avverrà quando si valuta, attraverso
l'ispezione della proprietà Terminated, se è il caso di iniziare un nuovo
ciclo.
A sentimento, l'effetto visivo dovrebbe essere quello tipico di varie
applicazioni in cui si preme un pulsante di annullamento a cui segue un
attimo di pausa in cui realmente l'applicazione termina l'operazione del
processo in corso, ma non prosegue ad eseguire le restanti operazioni del
processo.
Ho tralasciato qualcosa?
