[Thread] Détruit, mais jamais 'nil'
Bonjour à tous,
Je travaille en ce moment sur un projet sous Delphi 7. Je rentre directement dans le vif du sujet : j'utilise une classe TThApport, dérivée de la classe TThread pour exécuter un travail de calcul relativement long sans pour autant provoquer un freeze de l'interface utilisateur, ce à quoi ils sont destinés donc normalement.
Pour décrire sommairement la structure, j'ai donc une classe TDtDeper qui contient une liste nommée LThApport de TThApport :
Code:
1 2 3
| (...)
LThApport : array[1..20] of TThApport;
(...) |
Le code de la classe TTHApport :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
| unit ThreadApport;
interface
uses
Classes, Windows, DtPcDep, SysUtils, SyncObjs;
type
TThApport = class(TThread)
private
JD, JF, HD, HF : integer;
UnJour, UneHeure : integer;
FEvent : TEvent;
protected
procedure Execute; override;
procedure DoWork;
procedure OnTerminateProcedure(Sender : TObject);
public
ThPieceDep : TPieceDep;
ThreadTerminated : boolean;
constructor Create(CreateSuspended : boolean ; UnePieceDep : TPieceDep ; JDCall,JFCall,HDCall,HFCall : integer);
procedure Kill;
destructor Destroy; override;
end;
implementation
{ TThApport }
constructor TThApport.Create(CreateSuspended : boolean ; UnePieceDep : TPieceDep ; JDCall,JFCall,HDCall,HFCall : integer);
begin
inherited Create(CreateSuspended);
FreeOnTerminate := True;
ThreadTerminated := False;
ThPieceDep := UnePieceDep;
FEvent := TEvent.Create(nil, False, False, '');
JD := JDCall;
JF := JFCall;
HD := HDCall;
HF := HFCall;
UnJour := JDCall;
UneHeure := HDCall;
OnTerminate := OnTerminateProcedure;
end;
destructor TThApport.Destroy;
begin
//déchargez la mémoire ici si vous avez créé des objets
if FEvent <> nil then FreeAndNil(FEvent);
inherited;
end;
procedure TThApport.OnTerminateProcedure(Sender : TObject);
var
Tampon : string;
begin
ThreadTerminated := True;
end;
procedure TThApport.Kill;
begin
FEvent.SetEvent;
end;
procedure TThApport.Execute;
var
UnJour : integer;
UneHeure : integer;
//UneListeApport : TList;
Tampon : string;
begin
ThPieceDep.LApportGen.Clear;
while not Terminated do
begin
try
case FEvent.WaitFor(10) of
wrSignaled : Terminate;
wrTimeout : DoWork;
end;
finally
end;
end;
end;
procedure TThApport.DoWork;
var
UnApportTotal : Double;
begin
{Le boulot}
end;
end;
end. |
Lors d'évènements particuliers, je passe dans une structure qui gère la création d'un nouveau thread, ou encore l'arrêt / relance d'un thread selon l'élément sur lequel il travaille. Cette structure est implémentée dans une classe différente, TPiece. Pour récupérer la liste de thread, je fais en début de la fameuse structure un truc du style
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| (...)
DtDeper := Owner as TDtDeper;
(...)
//S'il faut lancer un nouveau thread
if NewThread then
begin
DtDeper.LThApport[PremierThreadLibre] := TThApport.Create(false, UnePiece, JD, JF, HD, HF);
end
else
begin
//On arrête le thread
DtDeper.LThApport[i].Kill;
//Et on le relance
DtDeper.LThApport[i] := TThApport.Create(false, UnePiece, JD, JF, HD, HF);
end;
(...) |
L'élément en question, nommé UnePiece, contient une liste reconstruite par le thread. J'associe un thread à chaque pièce, s'arrêtant si de nouvelles modifications sont apportées sur la pièce, et se relançant.
Jusqu'ici, rien de bien sorcier, et rien de bien intéressant ... Les soucis viennent plus tard. Mon premier, c'est qu'en debug, les threads ne se libèrent pas, alors que TrueOnTerminate est à true et qu'en mode pas à pas, ils passent bien dans le .Destroy : les éléments de la liste de thread ne sont jamais à 'nil'.
Pire, en debug toujours, les éléments de la liste de thread contiennent des infos différentes, suivant la classe d'où j'inspecte la liste de threads (TDtDeper ou TPiece).
Mon second souci, c'est que bien réutilisant les mêmes threads, qui ne sont jamais 'nil' puis 'Create' de nouveau, mais donc réinitialisés ... Et bien je bouffe 8 méga de ram à chaque passage dans un de mes threads. Même lorsque j'en réutilise un, je prends de nouveau 8 méga de ram.
Donc, j'ai plusieurs pistes, et j'ai besoin de votre aide :p
La première : je me plante dans la visibilité de ma liste de threads, je ne parle pas des mêmes lorsque je contrôle leur état dans les différentes classes. Du coup, ma gestion est foireuse.
La deuxième : si je détruis 'ThPieceDep' dans mon destroy de thread, je le détruis aussi dans ma liste de piece dans DtDeper, je ne peux donc pas le faire, mais est-ce que 'ThPieceDep' qui n'est donc pas détruit, n'empêche pas le destroy du thread de s'accomplir ? A ce moment là, dois-je travailler avec un pointeur pour ma fameuse pièce ?
Que de mots mal employés, je me rends compte que le problème exposé n'est pas très clair (moitié thread, moitié visibilité de variable), mais je suis un peu à cours de ressources, ayant parcouru un certain nombre de forums sur le sujet des threads. Bien que ce soit mon premier post, ça fait un moment que je parcours ce forum, je compte sur vous, et si j'ai mal expliqué un certain nombre de points, n'hésitez pas !
Merci d'avance, Risk.