Bonjour à tous !

Lorsque dans un thread (plusieurs instances) on a un code comme celui-ci :
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);
on s'attend à ce que SyncCount soit toujours à 1, que l'appel en cours se termine avant la prochaine synchronisation.

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.

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.
Pour retrouver le comportement logique, il faut englober Synchronize dans une section critique

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 ?