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.