PDA

Visualizza la versione completa : [DELPHI] Thread non "muore"


Whitecrowsrain
07-05-2009, 12:11
Salve a tutti
ho realizzato un'applicazione multi-Thread con Delphi 7 ed un grosso problema... un thread non ne vuole sapere di terminarsi e quindi nonostante l'applicativo si chiuda (o meglio l'interfaccia grafica si chiude) se vado sul taskManager vedo ancora attivo l'eseguibile del programma... cosa devo fare per ucciderlo?

ESSE-EFFE
07-05-2009, 13:07
Senza conoscere il codice del thread è un po' difficile aiutarti...

Whitecrowsrain
07-05-2009, 13:28
Costruttore:


constructor TAggiornaStato.create(q,q1,q2:TADOQuery;priorita:T ThreadPriority;vedi_storico:boolean);
begin
FreeOnTerminate:=false;
qry:=q;
qry2:=q1;
qry3:=q2;
esegui:=true;
inherited Create(False);
end;


Procedura che dovrebbe fermare l'elaborazione:


procedure TAggiornaStato.fermaElaborazione;
begin
esegui:=false;
end;


Procedure dell'execute :


procedure TAggiornaStato.Execute;
begin
updateState;
while (esegui) do
begin
try
if (Terminated) then
updateState;
except
on e:exception do
messageDlg('Errore Thread: '+trim(e.message),mtwarning,[mbOk],0);
end;
Sleep(4000);
end;
end;

quando lo termino faccio :



var
//dichiarato allinizio ovviamente
AGGST:TaggiornaStato;
...


begin
....
AGGST.fermaElaborazione
//attendo il terminate
repeat
until AGGST.terminate;
AGGST.free;
AGGST:=nil;
end;


Il problema è che ora alle volte rimane incatrato in quel ciclo...

ESSE-EFFE
07-05-2009, 14:54
Allora, la soluzione così al volo non ce l'ho, però posso darti qualche suggerimento:





esegui:=true;



Questa variabile "esegui" non ti serve. La usi esattamente per fare quello per cui la proprietà Terminated è preposta.





procedure TAggiornaStato.Execute;
begin
updateState;
while (esegui) do
begin
try
if (Terminated) then
updateState;
except
on e:exception do
messageDlg('Errore Thread: '+trim(e.message),mtwarning,[mbOk],0);
end;
Sleep(4000);
end;
end;



Il controllo del while fallo sulla proprietà Terminated. Poi non capisco una cosa: pare che questo thread richiami "updateState" all'inizio e quando termina, ma durante l'esecuzione non fa nulla, forse hai solo omesso delle parti non significative. Ovviamente la "updateState" finale la puoi mettere fuori dal ciclo while. Inoltre 4000ms di Sleep mi pare decisamente troppo. A proposito, la updateState è thread-safe vero? O aggiorna l'interfaccia grafica?





AGGST.fermaElaborazione
//attendo il terminate
repeat
until AGGST.terminate;



Meglio fare:

AGGST.Terminate();
AGGST.WaitFor();

(e comunque doveva essere AGGST.terminated).

Whitecrowsrain
08-05-2009, 02:23
Il terminate lo fa ogni qual volta finisce updateState (All'interno della funzione stessa).
Esegui mi serve per controllare meglio l'uscita dal thread, infatti la uso anche all'interno dell'updateState per fermare i cicli qualora fosse false (faccio delle interrogazioni al database e ciclicamente aggiorno una listView dell'interfaccia grafica richiamando un'altra funzione che sincronizzo).

Cmq credo di aver risolto il problema: io creavo il Thread durante l'esecuzione dell'evento OnShow della form principale. Ora l'ho spostato, per una necessità diversa, dentro ad un timer che richiamo dall'OnShow e il problema è svanito! Direi quindi che ho avuto un cosidetto colpo di cul...

Comunque la scelta dei 4 secondi è dettata dal fatto che questo thread serve a dare informazioni tramite l'interfaccia e deve coesistere con altri 4 che rappresentano invece il cuore del programma e non volevo appesantire troppo l'applicativo.

si è vero sarebbe meglio il AGGST.WaitFor() al posto del ciclo ma con il repeat io posso dare delle istruzioni all suo interno tipo application.processMessage tanto per non lasciare l'applicativo in stato di momentaneo blocco.

Cmq grazie per l'aiuto.

ESSE-EFFE
08-05-2009, 10:09
Il terminate lo fa ogni qual volta finisce updateState (All'interno della funzione stessa).


Questo non mi sembra il massimo, però dipende un po' dalla tua applicazione.



Esegui mi serve per controllare meglio l'uscita dal thread, infatti la uso anche all'interno dell'updateState per fermare i cicli qualora fosse false


Che significa "meglio"? Non ho ancora capito perchè non usi Terminated...



(faccio delle interrogazioni al database e ciclicamente aggiorno una listView dell'interfaccia grafica richiamando un'altra funzione che sincronizzo).


Se all'interno della updateState accedi ad una TListView, devi richiamarla con Synchronize. Non so se è questo che intendi con "funzione che sincronizzo", comunque è opportuno precisarlo.



Cmq credo di aver risolto il problema: io creavo il Thread durante l'esecuzione dell'evento OnShow della form principale. Ora l'ho spostato, per una necessità diversa, dentro ad un timer che richiamo dall'OnShow e il problema è svanito! Direi quindi che ho avuto un cosidetto colpo di cul...


Perchè dal thread accedi a componenti del form principale. Se lo fai senza Synchronize qualche problema ci sarà ancora. Il problema mi pare sia stato spostato, non risolto.



si è vero sarebbe meglio il AGGST.WaitFor()


Non è che sarebbe meglio, quello è il sistema corretto.



tanto per non lasciare l'applicativo in stato di momentaneo blocco.


L'applicativo non è in blocco, sta chiudendo i thread e questo puoi segnalarlo. Chiaro che se il tuo thread è appena entrato nello Sleep di 4 secondi per quel tempo non può certo chiudersi.



Cmq grazie per l'aiuto.

Figurati.

Whitecrowsrain
08-05-2009, 13:47
Originariamente inviato da ESSE-EFFE
Questo non mi sembra il massimo, però dipende un po' dalla tua applicazione.

Che significa "meglio"? Non ho ancora capito perchè non usi Terminated...

Perchè con terminate devo aspettare che finisca i cicli all'interno dell'updatestate che invece interrompo tramite dei controlli con la variabile esegui



Originariamente inviato da ESSE-EFFE
Se all'interno della updateState accedi ad una TListView, devi richiamarla con Synchronize. Non so se è questo che intendi con "funzione che sincronizzo", comunque è opportuno precisarlo.

Perchè dal thread accedi a componenti del form principale. Se lo fai senza Synchronize qualche problema ci sarà ancora. Il problema mi pare sia stato spostato, non risolto.


Si uso Synchronize ma se faccio partire il Thread nell'onShow poi si bloccava durante il terminate.




Originariamente inviato da ESSE-EFFE
L'applicativo non è in blocco, sta chiudendo i thread e questo puoi segnalarlo. Chiaro che se il tuo thread è appena entrato nello Sleep di 4 secondi per quel tempo non può certo chiudersi.

no lo sleep se esegui e false non lo fa(esempio di una ottimizzazine con la variabile esegui )

ESSE-EFFE
08-05-2009, 15:24
Perchè con terminate devo aspettare che finisca i cicli all'interno dell'updatestate che invece interrompo tramite dei controlli con la variabile esegui


Basandomi sul codice da te postato, la variabile esegui la utilizzi anche per terminare il thread. Quindi se anzichè controllare tale variabile all'interno della updateState utilizzi Terminated raggiungi esattamente lo stesso scopo (con la differenza che non aggiungeresti una variabile ridondante e non thread-safe nel programma).



no lo sleep se esegui e false non lo fa(esempio di una ottimizzazine con la variabile esegui )

Questo è fuorviante, oltre che sbagliato. Sempre ragionando sul tuo codice, se tu imposti esegui a false (oppure se richiami la Terminate) ed il tuo thread sta già eseguendo la Sleep (o comunque se il thread stesso non sta controllando il valore di esegui o di Terminated) il thread continuerà a fare quello che stava facendo.

Whitecrowsrain
08-05-2009, 22:38
Originariamente inviato da ESSE-EFFE
Basandomi sul codice da te postato, la variabile esegui la utilizzi anche per terminare il thread. Quindi se anzichè controllare tale variabile all'interno della updateState utilizzi Terminated raggiungi esattamente lo stesso scopo (con la differenza che non aggiungeresti una variabile ridondante e non thread-safe nel programma).

Questo è fuorviante, oltre che sbagliato. Sempre ragionando sul tuo codice, se tu imposti esegui a false (oppure se richiami la Terminate) ed il tuo thread sta già eseguendo la Sleep (o comunque se il thread stesso non sta controllando il valore di esegui o di Terminated) il thread continuerà a fare quello che stava facendo.

Il terminate non lo chiamo mai direttamente e nel caso che tu hai menzionato si perde solo qualche secondo ma nulla di più.. cmq ho fatto dei test ed ho visto che fin ora questo è risultato il sistema più performante.

E poi una variabile membro del thread di tipo booleano non è di fatto thread-safe?
Di certo hai ragione a dire che è ritondante, ma per il momento è una necessità.

Sicuramente Farò tesoro dei tuoi consigli e vedo se riesco a rendere più corretto il codice dell'applicazione.

Grazie ancora.

ESSE-EFFE
08-05-2009, 22:49
nel caso che tu hai menzionato si perde solo qualche secondo ma nulla di più..


Certo, ma io intendevo dire che quell'aspetto non lo ottimizzi di certo aggiungendo una variabile.



cmq ho fatto dei test ed ho visto che fin ora questo è risultato il sistema più performante.


Sono contento che a te vada bene, però consentimi di non essere d'accordo.



E poi una variabile membro del thread di tipo booleano non è di fatto thread-safe?


Forse "di fatto" sì e magari non ti darà mai problemi, ma non è una cosa sicura.



Di certo hai ragione a dire che è ritondante, ma per il momento è una necessità.


Se è ridondante non è una necessità. E non ho ancora capito il motivo di questa ridondanza.



Grazie ancora.


Di nulla.

Loading