Lorsque plusieurs threads s'exécutent en parallèle dans une application Delphi, il est crucial de bien les synchroniser pour éviter les conflits, les accès concurrents aux ressources partagées ou encore les blocages indésirables. Delphi offre plusieurs outils pour cela, mais l’un des plus puissants et élégants est sans doute la classe TEvent
, issue de l’unité System.SyncObjs
.
Que vous écriviez une application multithreadée simple ou complexe, TEvent
vous permet de mettre en pause, synchroniser ou relancer un ou plusieurs threads de manière fiable.
Plongée dans TEvent
Qu’est-ce que TEvent
?
TEvent
est un wrapper objet autour d’un handle d’événement Windows, qui sert à synchroniser les threads. C’est une classe qui permet à un thread d’attendre qu’un événement soit signalé par un autre thread.
Principales méthodes :
WaitFor
: met le thread en attente jusqu’à ce que l’événement soit signalé (ou que le délai soit écoulé).SetEvent
: signale que l’événement s’est produit (libère les threads en attente).ResetEvent
: remet l’événement à l’état non signalé (nécessaire en mode manuel).PulseEvent
: signale temporairement l’événement (déconseillé en pratique car non fiable).
On crée un TEvent
comme suit :
MyEvent := TEvent.Create(nil, True, False, '');
Paramètres :
ManualReset
: True pour réinitialiser manuellement, False pour auto-reset après signal.InitialState
: True si l'événement est signalé au départ.Name
: Nom système (souvent vide sauf usage spécifique).
Exemple simple : Synchroniser deux threads
Imaginons deux threads : un producteur qui signale quand une tâche est prête, et un consommateur qui attend ce signal pour commencer son travail.
var ReadyEvent: TEvent;
procedure Producer;
begin
Sleep(1000); // Simule un travail
Writeln('Producteur : tâche prête');
ReadyEvent.SetEvent; // Signal envoyé
end;
procedure Consumer;
begin
Writeln('Consommateur : en attente...');
if ReadyEvent.WaitFor(INFINITE) = wrSignaled then
Writeln('Consommateur : tâche reçue, je démarre !');
end;
begin
ReadyEvent := TEvent.Create(nil, True, False, '');
TThread.CreateAnonymousThread(Producer).Start;
TThread.CreateAnonymousThread(Consumer).Start;
end.
Ici, le consommateur reste bloqué sur WaitFor, jusqu’à ce que le producteur appelle SetEvent.
Exemple avancé : Plusieurs consommateurs avec auto-reset
En mode auto-reset, l’événement est automatiquement réinitialisé après qu’un seul thread ait été libéré. Très utile pour répartir des tâches entre plusieurs consommateurs.
var TaskEvent: TEvent;
procedure Consumer(ID: Integer);
begin
Writeln(Format('Thread %d en attente...', [ID]));
if TaskEvent.WaitFor(INFINITE) = wrSignaled then
Writeln(Format('Thread %d exécute la tâche !', [ID]));
end;
procedure Main;
var
I: Integer;
begin
TaskEvent := TEvent.Create(nil, False, False, ''); // auto-reset
for I := 1 to 3 do
TThread.CreateAnonymousThread(procedure begin Consumer(I); end).Start;
Sleep(1000);
Writeln('Main : envoi de tâches aux threads...');
TaskEvent.SetEvent; // Libère un seul thread
Sleep(500);
TaskEvent.SetEvent; // Libère un autre thread
end;
En auto-reset, chaque appel à SetEvent
libère un seul thread en attente.
Pour conclure
TEvent
est un outil puissant et élégant pour gérer la synchronisation des threads en Delphi.
Grâce à ses méthodes comme SetEvent
, ResetEvent
et WaitFor
, il permet de contrôler précisément le comportement des threads concurrents, en évitant les pièges classiques du multithreading comme les race conditions ou les blocages.
Que ce soit pour coordonner un producteur-consommateur ou répartir des tâches entre plusieurs threads, TEvent
est une solution solide à adopter dans vos projets Delphi multithreadés.