J'utilise depuis longtemps les Threads de façon simpliste ayant découvert les fonctions Suspend et Resume qui permettaient jusque là de ne pas se fatiguer les méninges ... ! En voulant adapter un simulateur sous FireMonkey , je découvre que ces deux méthodes sont obsolètes et la doc nous invite à utiliser à la place TEvent , TMutex , Semaphore et autres qui m'étaient jusque là étrangers . Tant les forums anglophones et francophones sont silencieux sur la question que j'ai du passer pas mal de temps à comprendre comment il fallait s'y prendre.
Finalement j'y suis à peu près parvenu mais je voudrais l'avis des virtuoses qui abondent ici !
Voilà : mon projet d'origine comporte un thread principal qui fait des calculs et trace en "temps réel" des vecteurs sur un composant graphique. Le thread secondaire sort un rapport textuel sur un simple TMemo et les transfère en liaison RS232 et en Wifi. Le thread secondaire est suspendu à chaque fois qu'il faut soit figer la simulation pour analyse, soit modifier des paramètres d'entrée. L'adaptation que je porte sous FMX est sous Delphi 10.4.2 Sydney edition.
Pour reproduire le processus très simplement ici , je simule le thread principal par du texte qui défile rapidement dans un Memo attribué au thread principal, et le thread secondaire avec un autre texte qui défile plus lentement. J'ai ajouté des boutons de RESUME et SUSPEND pour ce deuxième thread qui ne recourent pas aux méthodes obsolètes, bien sûr mais utilisent un TEvent suivant les conseils de la docwiki. Le TEvent est EV_STOP dans le code qui suit.
Voici l'unité du thread principal
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 unit UnTestThreadEvent; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Memo.Types, FMX.StdCtrls, FMX.Controls.Presentation, FMX.ScrollBox, FMX.Memo, UnTHREADTstEv, System.SyncObjs; type TForm1 = class(TForm) Memo1: TMemo; // memo du thread secondaire BtSuspend: TButton; BtResume: TButton; Memo2: TMemo; // memo du thread principal BtStart: TButton; BtQuit: TButton; Timer1: TTimer; procedure BtStartClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure BtQuitClick(Sender: TObject); procedure Timer1Timer(Sender: TObject); procedure BtSuspendClick(Sender: TObject); procedure BtResumeClick(Sender: TObject); private { Déclarations privées } public { Déclarations publiques } end; var Form1: TForm1; c1, c2 : integer; MThr : ThreadTstEvent; Ev_Stop : TEvent; Prempass : boolean = true; implementation {$R *.fmx} procedure TForm1.FormCreate(Sender: TObject); begin C1 := 0; C2 := 0; prempass := true; MThr := ThreadTstEvent.Create(true); // CreateSuspended MTHr.FreeOnTerminate := true; EV_STop := TEvent.Create(false); end; procedure TForm1.BtStartClick(Sender: TObject); var i : integer; begin c2 := 0; Timer1.Enabled := true; // process du thread principal end; procedure TForm1.BtResumeClick(Sender: TObject); //simule RESUME begin if prempass then begin MThr.Start; prempass := false; end else EV_STop.ResetEvent; end; procedure TForm1.BtSuspendClick(Sender: TObject); // simule SUSPEND begin Ev_STop.SetEvent; end; procedure TForm1.Timer1Timer(Sender: TObject); begin Memo2.Lines.Add (IntToStr (c2) + ' ligne(s) thread principal '); Memo2.GoToTextEnd; Inc (c2); end; procedure TForm1.BtQuitClick(Sender: TObject); begin MThr.Terminate; Close; end; end.
L'unité du thread secondaire est la suivante :
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 unit UnTHREADTstEv; interface uses System.Classes, System.SysUTILS, System.SyncObjs; type ThreadTstEvent = class(TThread) protected procedure Execute; override; end; implementation Uses UnTestThreadEvent; { ThreadTstEvent } procedure ThreadTstEvent.Execute; begin while NOT Terminated do begin Synchronize ( procedure begin Form1.Memo1.Lines.Add(IntToStr(c1) + ' ligne(s) Thread second'); Form1.Memo1.GoToTextEnd; Inc (C1); end); Sleep (500); if EV_Stop.WaitFor(100) = WrSignaled then begin Synchronize ( procedure begin Form1.Memo1.Lines.Append(' Thread en attente'); Form1.Memo1.GoToTextEnd; end); Sleep (1000); end; While EV_Stop.WaitFor(100) <> WrTimeOut do Sleep(50); end; end; end.
Voilà , à votre avis ?
Merci d'avance.
Partager