Bonjour à tous !
Lorsque dans un thread (plusieurs instances) on a un code comme celui-ci :
on s'attend à ce que SyncCount soit toujours à 1, que l'appel en cours se termine avant la prochaine synchronisation.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 Synchronize(procedure begin inc(SyncCount); // SyncCount = 1 ? Dec(SyncCount); end);
Sauf que si dans la procédure synchronisée on procède à la destruction d'un TThread, ce dernier attend la fin effective de sa tâche par un WaitFor qui relance un CheckSynchronize !
Résultat, un deuxième thread peut être autorisé à accéder au principal alors que la synchronisation précédente n'est pas terminée (TMonitor mal placé/utilisé ?) !
Voici une démo minimale pour illustrer cela. Ne la laissez pas tourner pendant des heures, le nombre de threads augmentant rapidement. Ctr+F2 pour aborter.
Pour retrouver le comportement logique, il faut englober Synchronize dans une section critique
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 unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; type TWorkerThread = class(TThread) protected procedure Execute; override; end; TSyncThread = class(TThread) protected procedure Execute; override; end; TForm1 = class(TForm) Label1: TLabel; procedure FormCreate(Sender: TObject); public WorkerThread :TWorkerThread; end; var Form1: TForm1; implementation {$R *.dfm} var SyncCount :integer; { TWorkerThread } procedure TWorkerThread.Execute; begin while not Terminated do Sleep(1000); end; { TSyncThread } procedure TSyncThread.Execute; begin while not Terminated do Synchronize(procedure begin inc(SyncCount); try Form1.Label1.Caption := 'SyncCount = ' +SyncCount.ToString; Form1.Label1.Update; FreeAndNil(Form1.WorkerThread); Form1.WorkerThread := TWorkerThread.Create; finally Dec(SyncCount); end; end); end; procedure TForm1.FormCreate(Sender: TObject); begin WorkerThread := TWorkerThread.Create; TSyncThread.Create; TSyncThread.Create; TSyncThread.Create; TSyncThread.Create; end; end.
Je suis en 10.4.2, est-ce que quelque sur un Delphi plus ancien observe le même comportement ou est-ce une régression ?
Partager