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 :
Le code de la classe TTHApport :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 (...) LThApport : array[1..20] of TThApport; (...)
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 : Sélectionner tout - Visualiser dans une fenêtre à part
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.
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.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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; (...)
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.
Partager