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