IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
logo

FAQ DelphiConsultez toutes les FAQ

Nombre d'auteurs : 124, nombre de questions : 934, dernière mise à jour : 23 octobre 2024  Ajouter une question

 

Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums Delphi et Delphi et bases de données de www.developpez.com et de l'expérience personnelle des auteurs.

Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose soient correctes. Les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous souhaitez y apporter des corrections ou la compléter, contactez un responsable (lien au bas de cette page).

Nous espérons que cette FAQ saura répondre à vos attentes. Nous vous en souhaitons une bonne lecture.

L'équipe Delphi de Developpez.com.

SommaireSystèmeThread (3)
précédent sommaire suivant
 

Note : ceci n'est pas un cours de programmation parallèle, mais juste une QR permettant de montrer aux débutants quelques avantages et inconvénients de la programmation multithread.

Sur un système d'exploitation comme Windows, toute application est décrite comme étant un processus. Un processus est autonome, isolé des autres processus (ils n'ont pas de zones mémoire en commun) et peut exécuter à peu près n'importe quel traitement (l'exception notable, mais non unique, étant l'accès type "driver").
Un processus est identifié, sur le système, par un numéro unique appelé PID (Process IDentifier). On accède à un processus via un handle, qui permet notamment de contrôler l'exécution du processus (fermeture, obtention du code de sortie…).
Un processus est également composé d'un ou plusieurs threads : le premier est appelé thread principal, c'est celui qui est lancé par le système d'exploitation lui-même. Les autres threads seront lancés par un (ou plusieurs) threads du processus.

Mais qu'est-ce qu'un thread ? C'est une unité d'exécution autonome, un "programme dans le programme". Un thread n'existe pas en dehors d'un processus hôte. Un thread est quasiment identique à un processus, à un détail près : les threads ne sont pas isolés, ils partagent le même espace mémoire, celui du processus hôte. Il est important de comprendre qu'un processus n'est, en fait, qu'une "structure de contrôle" : il n'est rien sans son thread principal, qui est le véritable élément exécutable d'un processus.
Bon, mais quel intérêt d'avoir des threads, alors ? Tout simplement que sur certaines opérations "longues", une application (son thread principal, en fait) est bloquée en attente d'une réponse. Le cas le plus connu est l'accès au disque dur, mais c'est en fait le cas de toutes les requêtes vers le système d'exploitation. Une application multithread, elle, peut mettre à profit ce "temps mort" pour exécuter d'autres tâches en attendant la réponse. C'est le système d'exploitation lui-même qui effectue cette détection et la commutation vers d'autres threads (le "passage de main"). Les communications réseau (surtout TCP/IP) profitent par exemple beaucoup du multithreading : pendant qu'un thread secondaire (dit "de communication") s'occupe des transactions sur les sockets, le thread principal peut toujours continuer de s'exécuter.
Sur une application Delphi, ceci permet par exemple de continuer à rafraîchir la fiche principale, de réagir aux actions utilisateur, etc. Un thread peut changer de priorité d'exécution, être suspendu, relancé, etc. Un thread existe même s'il est terminé : ceci notamment pour pouvoir récupérer son code de sortie depuis des threads actifs. Pour définitivement détruire un thread, il faut soit terminer son processus hôte, soit le détruire explicitement. Cependant, un thread terminé ne fait qu'occuper un peu de mémoire, il n'interfère plus dans le séquencement des threads réalisé par le système d'exploitation.
Le principal problème avec les threads, c'est la notion d'accès concurrent, de synchronisation et de réentrance. En effet, le développeur ne peut pas déterminer quand le système d'exploitation va stopper le thread courant pour en exécuter un autre, ni quand le contrôle d'exécution lui reviendra de nouveau.

Accès concurrent :
L'accès concurrent, c'est lorsque deux threads tentent d'accéder à la même donnée "en même temps". En général, ce n'est jamais réellement en même temps, sauf sur un système multiprocesseur. C'est plutôt qu'un thread A accédant à une ressource R a été interrompu, pendant cet accès, par un thread B utilisant lui aussi la même ressource R.
Dans certains cas, ceci n'a aucune importance : par exemple, pour la lecture d'une variable globale. Mais la plupart du temps, c'est critique : par exemple, si deux threads tentent d'incrémenter une variable donnée… Qui va "gagner" ? C'est impossible à déterminer sans mécanismes de synchronisation.

Synchronisation :
Le système d'exploitation fournit ce que l'on appelle des mécanismes de synchronisation pour permettre à deux threads concurrents de ne pas s'interrompre mutuellement. Ainsi, deux threads synchronisés ne peuvent pas se gêner mutuellement. Il existe plusieurs niveaux de synchronisation : soit uniquement entre les threads d'un même processus (synchronisation inter-threads), soit entre les processus du système (synchronisation inter-processus). Bien sûr, tout élément de synchronisation inter-processus peut également être utilisé pour une synchronisation inter-threads, mais c'est en général plus lourd et plus lent que les mécanismes locaux.
Les plus utilisés sont les sections critiques (inter-threads), les mutex (inter-processus), les évènements (inter-processus) et les messages (inter-processus).
Éléments de synchronisation VCL : Unités "SyncObjs.pas" et "SysUtils.pas".
Éléments de synchronisation Win32 : Liens MSDN : Using Critical Section Objects, fonction CreateMutex, fonction CreateEvent, fonction SendMessage.

Réentrance :
La réentrance, c'est le fait qu'une fonction puisse être interrompue par elle-même. Typiquement, toutes les fonctions natives de la VCL (pas vos gestionnaires d'évènements, par exemple, mais des fonctions comme Format) et de l'API Win32 sont réentrantes, c'est à dire qu'il est possible d'appeler la même fonction au sein de plusieurs threads (voire processus) sans ajouter de protection particulière.

Certaines fonctions de la VCL (comme MessageDlg) ne doivent être appelées que depuis le thread principal de l'application. Le problème n'est pas lié à la réentrance de la fonction, mais à son contexte d'exécution.

Toute fonction qui n'utilise que ses paramètres et des variables locales est forcément réentrante : donc, une fonction de calcul "pur" est réentrante. Par contre, toute fonction utilisant une ressource globale directement (variable globale, instance de fiche…) n'est plus réentrante, et devra donc être protégée par un mécanisme de synchronisation. On parle également de ressource critique. Toute la fonction n'est pas à protéger, cependant : seules les lignes de code utilisant la ressource critique doivent être encadrées par une synchronisation.
Exemple de fonction réentrante :

Code delphi : Sélectionner tout
1
2
3
4
Function Reentrant ( Const A, B : Extended ) : Extended ; 
Begin 
     Result:=A*B; 
End;
Cette fonction, même interrompue par elle-même, ne peut produire de résultat erroné car Delphi assure que les paramètres d'une fonction et ses variables locales sont uniques pour chaque appel à une fonction/procédure. En bref, la fonction est réentrante parceque Delphi est un langage procédural.
Les fonctions utilisant des paramètres Var ne sont en général pas réentrantes.

Exemple de fonctions non-réentrante :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
Var 
   GlobalVariable : Integer ; 
  
Procedure NonReentrant ( Const Value : Integer ) ; 
Begin 
     If (GlobalVariable>0) Then GlobalVariable:=Value 
                           Else GlobalVariable:=GlobalVariable-1; 
End;
En fonction de l'endroit où la fonction est interrompue par elle-même, le résultat produit peut être absolument n'importe quoi : cette fonction n'est pas compatible avec les threads (on dit qu'elle n'est pas thread-safe). Cependant, on peut la rendre réentrante "de force" grâce à une section critique :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Var 
   GlobalVariable : Integer ; 
   GlobalVariableCriticalSection : TCriticalSection ; 
  
Procedure ForcedReentrant ( Const Value : Integer ) ; 
Begin 
     GlobalVariableCriticalSection.Enter; 
     // A partir de ce moment, AUCUN thread utilisant cette section critique ne peut interrompre 
     // l'exécution. Ceci inclut bien entendu la fonction ForcedReentrant elle-même. 
     If (GlobalVariable>0) Then GlobalVariable:=Value 
                           Else GlobalVariable:=GlobalVariable-1; 
     GlobalVariableCriticalSection.Leave; 
     // La section critique est terminée, et les autres threads l'utilisant peuvent désormais 
     // interrompre l'exécution. Cependant, c'est désormais sans risques, l'accès à la variable 
     // globale est terminé. 
End;
Interblocage :
Le principal risque de la programmation parallèle est l'interblocage. Ce terme signifie que deux threads (ou plus) sont en attente d'un élément verrouillé par un autre thread. Typiquement, ceci correspond à une situation de ce type :
  • Le thread A verrouille une section critique CS1.
  • Le thread B verrouille une section critique CS2.
  • Au sein du thread A, on demande à verrouiller CS1 : le thread est bloqué, car le thread B la possède déjà.
  • Au sein du thread B, on demande à verrouiller CS2 : le thread est bloqué, car le thread A la possède déjà.
  • Aucun des deux threads ne peut continuer à s'exécuter : or, pour débloquer la situation, un des deux doit libérer sa propre CS, ce qui est impossible. Les threads sont interbloqués.

Il existe de nombreuses formes d'interblocage, mais elles ont toutes un point commun : l'interblocage se produit lorsque la synchronisation entre les threads est mal conçue (mauvais type de synchronisation, par exemple une synchronisation inter-threads alors qu'il en faudrait une inter-processus, attente d'un évènement inexistant…), ou mal implémentée (libération d'une section critique trop tôt ou trop tard, oubli de libération…).

Mis à jour le 14 janvier 2014 Mac LAK

Note : ceci n'est pas un cours de programmation parallèle, mais juste une QR permettant de montrer aux débutants les prémices de l'utilisation des threads avec la VCL.
Créer un thread sous Delphi se fait en ajoutant un objet dérivé de TThread à l'application.
Cette classe est déclarée dans l'unité "Classes.pas". Cependant, contrairement aux contrôles classiques (comme par exemple TTimer, TButton…), cette classe ne sait presque rien faire nativement : il faut la surcharger pour définir ce qu'elle fera au sein du programme.

Ajout d'un nouveau thread : Sur un projet ouvert, faites "Fichier", "Nouveau", "Autres" et choisissez "Objet Thread" (sur l'onglet "Nouveau"). L'assistant de Delphi va alors proposer une boîte de dialogue, permettant de nommer le nouveau type de thread. Appelons-le "TTestThread" pour l'exemple. Ne cochez pas la case créant un thread nommé.
Delphi va alors créer une nouvelle unité, déclarant le nouveau thread. Le code ajouté est celui-ci :

Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
unit Unit1; 
  
interface 
  
uses Classes; 
  
type 
  TTestThread = class(TThread) 
  private 
    { Déclarations privées } 
  protected 
    procedure Execute; override; 
  end; 
  
implementation 
  
{ TTestThread } 
  
procedure TTestThread.Execute; 
begin 
  { Placez le code du thread ici } 
end; 
  
end.
Note : des commentaires ont été supprimés par rapport au code réellement généré par Delphi.

Lors du lancement du thread, c'est la méthode Execute qui, comme son nom l'indique, sera exécutée dans un thread séparé. Lorsque l'on sort de cette procédure, le thread s'arrête.
Un thread peut par exemple être utilisé pour effectuer une opération relativement longue tout en permettant à la fenêtre principale d'être mise à jour et de réagir. Ceci est nécessaire si l'on veut, par exemple, pouvoir interrompre le traitement.
Pour tester si le thread doit s'arrêter, la VCL fournit une propriété booléenne Terminated, qui permet de savoir au sein même de la méthode Execute si l'on a demandé l'arrêt du thread.
En général, la méthode est implémentée suivant ce schéma :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
procedure TTestThread.Execute; 
begin 
     While Not Terminated Do 
           Begin 
           { Placez le code du thread ici } 
           End; 
end;
La classe TThread implémente également une fonction de synchronisation avec la VCL, nommée Synchronize. Cette fonction prend en argument l'adresse d'une méthode (sans arguments, ni retour), et l'exécute sans entrer en conflit avec la VCL. Ceci est crucial si, par exemple, le thread met à jour une barre de progression ou un TStringGrid et que l'utilisateur clique sur un contrôle : il peut alors se produire un interblocage sévère au sein de la VCL.
Exemple d'une méthode devant être synchronisée :
Code delphi : Sélectionner tout
1
2
3
4
procedure TTestThread.UpdateForm; 
begin 
     Application.MainForm.Title:=Format("Progression : %d %%",[CurrentPercentDone]); 
end;
L'appel se fait en insérant Synchronize(UpdateForm); dans le code. La création du thread lui-même est très simple :
Code delphi : Sélectionner tout
1
2
3
4
5
6
Var 
   MyThread : TTestThread ;   // A déclarer de préférence en attribut d'une fiche. 
Begin 
     MyThread:=TTestThread.Create(False); 
     // Le thread est désormais créé, et actif. 
End;
Arrêter le thread est également très simple :
Code delphi : Sélectionner tout
1
2
3
4
// On demande au thread de s'arrêter "proprement". 
MyThread.Terminate; 
// Maintenant, on attend sa fermeture réelle. 
ExitCode:=MyThread.WaitFor;
Que faire dans un thread, et comment le faire ?
Le sujet est beaucoup trop vaste pour une QR, et il y a de fortes chances que ce soit spécifique à l'application développée. Vous êtes encouragés à exposer votre problème sur le forum. Sachez toutefois que l'aide Delphi de la classe TThread est plus qu'indispensable : vous n'arriverez même pas à exposer votre problème correctement si vous n'êtes pas un minimum familier avec la classe TThread.

Comment passer des paramètres ?
La manière la plus simple de procéder est de déclarer des attributs de la classe. On démarre le thread en état suspendu (créer le thread avec le paramètre True passé au constructeur), on initialise les attributs de classe, puis on relance le thread (méthode Resume).
Exemple :
Code delphi : Sélectionner tout
1
2
3
4
MyThread:=TTestThread.Create(True);   // Thread créé en état "Suspendu". 
MyThread.FreeOnTerminate:=True;       // Libération automatique de l'objet lorsque le thread se termine. 
MyThread.Priority:=tpHighest;         // Thread de haute priorité. 
MyThread.Resume;                      // Thread relancé, et actif.
Adéquation des threads VCL : Les threads créés par la VCL via une classe dérivée de TThread sont parfaits pour tout traitement "permanent" au sein de l'application, car ils permettent un contrôle beaucoup plus facile de l'exécution depuis le thread principal de l'application.
Egalement, ils sont idéaux lorsque l'on doit accéder à des éléments des fiches (mise à jour de contrôles, par exemple).

Cependant, ils sont plutôt lourds à gérer pour des opérations de traitement ponctuelles, ou des opérations "simples" mais nombreuses : typiquement, une opération à exécuter dans un thread, mais une seule fois. Le fait que le thread reste actif n'a alors non seulement aucun intérêt, mais est même ennuyeux. On désire simplement exécuter une fonction dans un thread séparé, et "terminer" le thread dès que la fonction est elle-même terminée.
En effet, dans le cas où l'on désire implémenter une série de fonctions unitaires simples, mais tournant dans un thread séparé, on se retrouve souvent à devoir soit implémenter une dérivée de TThread par fonction de traitement (ce qui est très lourd au niveau code), soit à devoir implémenter une machine à états dans la méthode Execute (ce qui est encore plus lourd).
Dans ce cas de figure, il est préférable d'utiliser des threads Win32.

Mis à jour le 14 janvier 2014 Mac LAK

Note : ceci n'est pas un cours de programmation parallèle, mais juste une QR permettant de montrer aux débutants les prémices de l'utilisation des threads avec l'API Win32.
Créer un thread en utilisant l'API Win32 se fait bien entendu en utilisant des fonctions dédiées, notamment CreateThread. Avec l'API Win32, toute fonction respectant un certain prototype peut devenir un thread. Ce prototype est déclaré via le type TFNThreadStartRoutine, défini comme suit :

Code delphi : Sélectionner tout
1
2
Function TFNThreadStartRoutine ( lpParameter : Pointer ) :  
LongWord ; stdcall ;
Donc, toute fonction prenant en argument un pointeur, renvoyant un LongWord (ou Cardinal, ou DWORD) et en convention d'appel stdcall peut devenir un thread.

Il est impératif d'utiliser une fonction classique, pas une méthode d'objet !

La création d'un thread est donc faite par l'appel de CreateThread. Cependant, les paramètres de cette fonction ne sont pas d'un usage évident pour le néophyte : nous allons donc présenter un code d'appel "simplifié".
Code delphi : Sélectionner tout
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
Function MyThreadProc ( lpParam : Pointer ) : LongWord ; stdcall ; 
Var 
   MyRealParam : PByteArray ; 
Begin 
     // À ce moment, on peut utiliser un transtypage pour récupérer le contenu "réel" 
     // du paramètre lpParam : ça peut être une adresse de tableau, l'adresse d'un Record, 
     // une instance d'un objet particulier, etc... 
     MyRealParam:=PByteArray(lpParam); 
     // Code du thread... 
     .... 
  
     // Utiliser UNE des versions suivantes pour terminer le thread. 
     // ERROR_SUCCESS vaut zéro, c'est le code de retour "OK" par  
convention. 
  
     // Sortie du thread (avec code de retour, version 1) 
     ExitThread(ERROR_SUCCESS) ;   // On sort immédiatement de la fonction,  
comme avec Exit. 
     // Sortie du thread (avec code de retour, version 2) 
     Result:=ERROR_SUCCESS ;       // Le code de retour est positionné, mais  
le thread reste actif. 
     Exit ;                        // Sortie réelle. 
     // Sortie du thread (sans code de retour) 
     Exit; 
End; 
  
Var 
     DataBlock : TByteArray ;  // Paramètre du thread. 
     ThreadID  : DWORD      ;  // Thread ID du nouveau thread. 
     hThread   : HANDLE     ;  // Handle sur le nouveau thread. 
  
Begin 
     // Les deux paramètres principaux sont le 3ème (adresse de la fonction)  
et 4ème (paramètres de la fonction). 
     // Le dernier sert à récupérer le ThreadID du nouveau thread. 
     hThread:=CreateThread(Nil,Nil,@MyThreadProc,@TByteArray,0,ThreadID); 
     If (hThread=0) Then 
        Raise Exception.Create('Impossible de créer le thread.'); 
     // Désormais, les variables hThread et ThreadID sont valides. 
     // Il ne faut JAMAIS "perdre" ces variables, sinon le thread risque de  
devenir 
     // totalement innaccessible, voire incontrôlable. 
End.
Les deux identifiants du thread que sont le ThreadID et un handle sont très différents :
  • Le ThreadID est valide et utilisable dans tous les threads du processus, et pour les autres processus du système. Il est unique sur l'ensemble du système d'exploitation.
  • Le handle retourné est local au thread ayant appelé CreateThread. Pour créer un nouveau handle sur le thread dans un autre thread, il sera nécessaire d'appeler la fonction OpenThread, qui prend le ThreadID en paramètre. Il est possible d'avoir autant de handles que l'on veut sur un même thread, et ils seront tous différents.

Pour simplifier, on résumer les rôles de ces deux paramètres ainsi :
  • Le ThreadID ne sert qu'à retrouver le thread au sein du système d'exploitation, ou pour envoyer des messages à un thread donné.
  • Un handle sert dans tous les autres cas : changement de priorité, suspension, reprise, terminaison brutale, attente de la fin du thread, etc.


Tant qu'il existe au moins un handle ouvert sur un thread, celui-ci n'est pas "détruit" réellement par le système : il est donc possible de récupérer son code de sortie par exemple. Une fois le dernier handle fermé et le thread terminé, il n'est plus possible d'y accéder de nouveau. Un handle est fermé par l'appel de la fonction CloseHandle.

Par exemple, le code ci-dessous va lancer un thread "librement", en priorité basse, et va le laisser se terminer tout seul :
Code delphi : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Var 
   hThread  : HANDLE ; 
   ThreadID : DWORD  ; 
Begin 
     // Création du thread, sur la procédure MyThreadProc. 
     hThread:=CreateThread(Nil,Nil,@MyThreadProc,@MyThreadParam,0,ThreadID); 
     If (hThread=0) Then 
        Raise Exception.Create('Impossible de créer le thread.'); 
     // Changement de priorité : priorité basse. 
     SetThreadPriority(hThread,THREAD_PRIORITY_LOWEST); 
     // Fermeture du handle : on va simplement attendre que le thread se  
termine tout seul. 
     CloseHandle(hThread); 
End.
Comment passer plus de paramètres ?
La manière la plus simple de procéder est de passer l'adresse d'un Record, défini suivant les besoins. Par exemple, si l'on doit passer au thread un Integer, un Extended et un PChar :
Code delphi : Sélectionner tout
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
Type 
    PThreadParam = ^TThreadParam ; 
    TThreadParam = Record 
       IntParam  : Integer  ; 
       RealParam : Extended ; 
       StrParam  : PChar    ; 
       End                  ; 
  
// On déclare la procédure de thread directement avec un PThreadParam, pour  
plus de facilité. 
Function MyThreadProc ( Param : PThreadParam ) : LongWord ; stdcall ; 
Begin 
     If (Param^.IntParam>0) Then 
        ... 
     .... 
End; 
  
Var 
   // La variable utilisée en paramètre est globale. 
   ThreadParam : TThreadParam ; 
  
Procedure RunThread ; 
Begin 
     With ThreadParam Do 
          Begin 
          IntParam:=546123; 
          RealParam:=3.14159; 
          StrParam:=PChar('Chaîne en paramètre'); 
          End; 
     CloseHandle(CreateThread(Nil,Nil,@MyThreadProc,@ThreadParam,0,Nil)); 
End;
Si vous passez à un thread une variable locale comme paramètre, il est fort probable que vous obteniez de sévères dysfonctionnements, voire une violation d'accès. En effet, la fonction créatrice (appelant CreateThread) continue son exécution, et ses variables locales sont détruites lorsque l'on en sort. Si le thread nouvellement créé tente d'accéder à des données qui n'existent plus, cela risque fort de causer de graves erreurs.

Voici la même version, mais sécurisée :
Code delphi : Sélectionner tout
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
Function MyThreadProc ( Param :  
PThreadParam ) : LongWord ; stdcall ; 
Var 
   MyPrivateParam : TThreadParam ;   // Copie locale au thread des  
paramètres. 
Begin 
     // Recopie des paramètres, puis libération de la mémoire. 
     CopyMemory(@MyPrivateParam,Param,Sizeof(MyPrivateParam)); 
     LocalFree(Param); 
     // Désormais, il est inutile de se préoccuper de libérer la mémoire :  
     // même en cas de crash, il n'y aura pas de fuite mémoire. 
     // Traitement normal, les paramètres sont sécurisés désormais. 
     If (MyPrivateParam.IntParam>0) Then 
        ... 
     .... 
End; 
  
Procedure RunThread ; 
Var 
   ThreadParam : PThreadParam ;   // La variable utilisée est un pointeur  
local. 
Begin 
     // On alloue, via l'API Win32, une zone pour les paramètres du thread. 
     ThreadParam:=PThreadParam(LocalAlloc(LPTR,sizeof(TThreadParam))); 
     With ThreadParam^ Do 
          Begin 
          IntParam:=546123; 
          RealParam:=3.14159; 
          StrParam:=PChar('Chaîne en paramètre'); 
          End; 
     // On crée le thread, c'est lui qui libèrera la mémoire. 
     CloseHandle(CreateThread(Nil,Nil,@MyThreadProc,ThreadParam,0,Nil)); 
End;
Pourquoi libérer la mémoire en tout début de thread ? Au cas où, lors de l'exécution du thread, une exception non-gérée serait levée, ou si l'appelant (pour une raison quelconque) décide de tuer le thread brutalement (fonction TerminateThread) : les variables locales sont toujours libérées, même en cas de crash. Les variables allouées, elles, ne le sont pas et provoquent donc des fuites mémoire.

Que faire dans un thread, et comment le faire ?
Le sujet est beaucoup trop vaste pour une QR, et il y a de fortes chances que ce soit spécifique à l'application développée. Vous êtes encouragés à exposer votre problème sur le forum.
Sachez toutefois que l'aide Win32 (disponible sur MSDN) est plus qu'indispensable : vous n'arriverez même pas à exposer votre problème correctement si vous n'êtes pas un minimum familier avec cette API.

Adéquation des threads Win32 :
Les threads créés via l'API Win32 sont parfaits pour tout traitement ponctuel, autonome et n'ayant pas besoin d'être surveillé par l'application principale. Ils sont par exemple extrêmement pratiques pour effectuer une copie de fichier en tâche de fond, ou la vérification d'une mise à jour sur Internet. N'oubliez pas qu'au sein d'un thread Win32, vous pouvez parfaitement créer un TClientSocket !

Cependant, ils sont très lourds à gérer si l'on doit contrôler finement l'exécution : suspension du thread, exécution asynchrone de code, vérification d'activité, etc. Un thread "permanent" dans votre application créé via l'API Win32 est très difficile à contrôler par rapport à un thread VCL. De même, si l'on doit accéder à la fiche principale, les risques d'interblocage sont très importants et deviennent vite complètement ingérables. Pour ce genre d'utilisation, il est préférable d'utiliser des threads VCL.

Mis à jour le 14 janvier 2014 Mac LAK

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.