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

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Composants FMX Delphi Discussion :

"TThread.Suspend et TThread.Resume deprecated " .. mais encore ?


Sujet :

Composants FMX Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Retraité
    Inscrit en
    Août 2018
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Août 2018
    Messages : 14
    Par défaut "TThread.Suspend et TThread.Resume deprecated " .. mais encore ?
    J'utilise depuis longtemps les Threads de façon simpliste ayant découvert les fonctions Suspend et Resume qui permettaient jusque là de ne pas se fatiguer les méninges ... ! En voulant adapter un simulateur sous FireMonkey , je découvre que ces deux méthodes sont obsolètes et la doc nous invite à utiliser à la place TEvent , TMutex , Semaphore et autres qui m'étaient jusque là étrangers . Tant les forums anglophones et francophones sont silencieux sur la question que j'ai du passer pas mal de temps à comprendre comment il fallait s'y prendre.

    Finalement j'y suis à peu près parvenu mais je voudrais l'avis des virtuoses qui abondent ici !
    Voilà : mon projet d'origine comporte un thread principal qui fait des calculs et trace en "temps réel" des vecteurs sur un composant graphique. Le thread secondaire sort un rapport textuel sur un simple TMemo et les transfère en liaison RS232 et en Wifi. Le thread secondaire est suspendu à chaque fois qu'il faut soit figer la simulation pour analyse, soit modifier des paramètres d'entrée. L'adaptation que je porte sous FMX est sous Delphi 10.4.2 Sydney edition.

    Pour reproduire le processus très simplement ici , je simule le thread principal par du texte qui défile rapidement dans un Memo attribué au thread principal, et le thread secondaire avec un autre texte qui défile plus lentement. J'ai ajouté des boutons de RESUME et SUSPEND pour ce deuxième thread qui ne recourent pas aux méthodes obsolètes, bien sûr mais utilisent un TEvent suivant les conseils de la docwiki. Le TEvent est EV_STOP dans le code qui suit.

    Nom : TestThreadTEvent.png
Affichages : 572
Taille : 16,1 Ko

    Voici l'unité du thread principal

    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
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    unit UnTestThreadEvent;
     
    interface
     
    uses
      System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
      FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Memo.Types,
      FMX.StdCtrls, FMX.Controls.Presentation, FMX.ScrollBox, FMX.Memo, UnTHREADTstEv,
      System.SyncObjs;
     
    type
      TForm1 = class(TForm)
        Memo1: TMemo;                   // memo du thread secondaire
        BtSuspend: TButton;
        BtResume: TButton;
        Memo2: TMemo;                    // memo du thread principal
        BtStart: TButton;
        BtQuit: TButton;
        Timer1: TTimer;
        procedure BtStartClick(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure BtQuitClick(Sender: TObject);
        procedure Timer1Timer(Sender: TObject);
        procedure BtSuspendClick(Sender: TObject);
        procedure BtResumeClick(Sender: TObject);
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
     
    var
      Form1: TForm1;
      c1, c2 : integer;
      MThr :  ThreadTstEvent;
      Ev_Stop  : TEvent;
      Prempass : boolean = true;
     
    implementation
     
    {$R *.fmx}
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
     C1 := 0;
     C2 := 0;
     prempass := true;
     MThr := ThreadTstEvent.Create(true);    // CreateSuspended
     MTHr.FreeOnTerminate := true;
     EV_STop := TEvent.Create(false);
     
    end;
     
    procedure TForm1.BtStartClick(Sender: TObject);
    var i : integer;
    begin
      c2 := 0;
     Timer1.Enabled := true;                    // process du thread principal
    end;
     
     
    procedure TForm1.BtResumeClick(Sender: TObject);   //simule RESUME
    begin
     if prempass then
      begin
          MThr.Start;
          prempass := false;
      end
      else EV_STop.ResetEvent;
     
    end;
     
     
    procedure TForm1.BtSuspendClick(Sender: TObject);  // simule SUSPEND
    begin
       Ev_STop.SetEvent;
    end;
     
     
     
    procedure TForm1.Timer1Timer(Sender: TObject);
    begin
      Memo2.Lines.Add (IntToStr (c2) + ' ligne(s) thread principal ');
      Memo2.GoToTextEnd;
      Inc (c2);
    end;
     
     
     
    procedure TForm1.BtQuitClick(Sender: TObject);
    begin
      MThr.Terminate;
      Close;
    end;
     
    end.

    L'unité du thread secondaire est la suivante :

    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
    unit UnTHREADTstEv;
     
    interface
     
    uses
      System.Classes, System.SysUTILS, System.SyncObjs;
     
    type
      ThreadTstEvent = class(TThread)
      protected
        procedure Execute; override;
     
      end;
     
    implementation
     
    Uses UnTestThreadEvent;
     
    { ThreadTstEvent }
     
    procedure ThreadTstEvent.Execute;
     
    begin
     
      while NOT Terminated do
     
      begin
         Synchronize (
         procedure
         begin
            Form1.Memo1.Lines.Add(IntToStr(c1) + ' ligne(s) Thread second');
            Form1.Memo1.GoToTextEnd;
            Inc (C1);
         end);
         Sleep (500);
     
         if EV_Stop.WaitFor(100) = WrSignaled then
         begin
             Synchronize (
             procedure
             begin
               Form1.Memo1.Lines.Append(' Thread en attente');
               Form1.Memo1.GoToTextEnd;
             end);
             Sleep (1000);
         end;
     
         While EV_Stop.WaitFor(100) <> WrTimeOut do  Sleep(50);
     
      end;
     
    end;
     
     
    end.

    Voilà , à votre avis ?

    Merci d'avance.

  2. #2
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 086
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 086
    Par défaut
    Citation Envoyé par jptrol Voir le message
    Le thread secondaire est suspendu à chaque fois qu'il faut soit figer la simulation pour analyse, soit modifier des paramètres d'entrée.
    Autant le détruire et le reconstruire ?
    c'est tellement plus simple

    Peut-être faudrait réflechir à une autre conception, là tu sembles vouloir reproduire Suspend/Resume au lieu de vraiment repenser la logique


    Si tu veux le conserver et qu'il attente que la configuration soit utilisable, un simple Booléen + TEvent pour indiquer que le Boolean à changer de valeur entre On Off
    Je gèrerais
    - Signaled = ON OFF
    - TimeOut = Vérifier le Terminated en cas d'arrêt du programme

    Pourquoi mélanger Sleep et WaitFor ?
    autant tout faire en WaitFor !



    Autre point, EV_Stop devrait être un membre privé de ThreadTstEvent
    Une property avec un accesseur SetActive modifie FActive et fait le SetEvent
    Modifier aussi TerminatedSet pour déclencher le SetEvent et provoquer un arrêt plus rapide du thread lors de l'arrêt du programme


    A quoi sert un thread qui fait comme unique fonction un Synchronize ?
    Sinon le WaitFor, oui c'est pertinent couplé avec une TThreadList par exemple

    Si au final toutes les opérations sont dans des Synchronize, autant faire un Timer ou jouer sur un OnIdle + un Délai du dernier affichage

    J'utilise beaucoup les threads,

    soit en One shot pour paralléliser une fonction bloquante lente et conserver la GUI réactive (voir gérer une annulation) et un simple Synchronize dans ce cas pour une éventuelle progression

    Ou alors des threads infinis qui utilisent un TThreadList + TEvent pour faire une file d'attente de traitement, généralement leur résultat est lui même envoyé à un autre thread qui gère une FIFO
    Même le MainThread, je gère un tampon donné + section critique pour le retour de donnée et j'utilise OnIdle pour aspirer les données (souvent uniquement de l'affichage), là j'évite le Synchronize, je préfère alimenter le tampon, après tout, dessiner à l'écran cela a un cout, que je préfère laisser au MainThread sans que cela impact la performance des threads (surtout lorsqu'il y a une centaine par exemple pour simulateur qui sert de Stress Test applicatif)


    J'utiliserais une TThreadList de TStringList interne au TThread, les rapports texte y sont placés.
    Et le MainThread lorsqu'il n'a pas mieux à faire OnIdle/OnTimer, consulte la liste,
    attention,
    - lock,
    - First TStringList (juste un transfert de pointeur ) + Delete(0)
    - UnLock
    et enfin il l'affiche la TStringList , toujours dans l'idée de ne pas bloquer le Thread de calcul durant le temps d'affichage dans le TMemo.

    Parfois je pousse le vice à utiliser une liste chainée plutôt ou un une Ring List (principe du Ring Buffer) qui permet de gagner du temps en évitant le Delete gérant un indice d'entrée et un indice de sortie ...
    en D7 cela faisait gagner du temps sur le Move.
    en FastMM, disons que l'on peut se permettre moins d'effort sur les petites manipulations mémoire.





    Si tu utilises du RS232 et Wifi, genre du composant TComPort ou TClientSocket*, je ferais
    - un Thread de lecture de la donnée, il ne fait que lire rien de plus, il transfère le buffer
    - Un thread qui se charge du cumuler les buffer et de les décomposer ensuite, selon ton protocole on peut très bien recevoir plusieurs trames d'un coup ou inversement des fragments à concaténer.
    - je ferais un ou plusieurs thread de traitement dans un pool selon complexité de traitement,

    * à savoir que lorsque l'on reçoit beaucoup de donnée par TCP/IP, il faut vider le buffer IP assez vite car il peut saturer si le traitement des trames est plus long que le débit d'entrée.
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 933
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 933
    Par défaut
    De manière générale la logique devrait être inverse ; le thread secondaire devrait attendre indéfiniment un ordre de démarrage. Ainsi tant qu'il est en attente, il ne consomme aucun temps CPU contrairement à ton code actuel par boucle qui nécessite une planification par l'OS.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    while TRUE do
    begin
      EV_Start.WaitFor(INFINITE);
     
      if Terminated then Exit;
     
      // Traitement
    end;
    Et pour terminer définitivement le thread puisqu'il est en attente infinie, il faut signaler l'event en surchargeant TerminatedSet.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    procedure ThreadTstEvent.TerminatedSet;
    begin
      inherited;
      EV_Start.SetEvent;
    end;
    Il faudra également prendre grand soin de la durée de vie du TEvent puisque le même objet est utilisé dans deux threads. Sinon tu risques la VA dans l'un ou l'autre à sa destruction.

  4. #4
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 086
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 086
    Par défaut
    Si tu as besoin d'une fréquence de traitement régulier à 500 ms, tu peux gérer un Delay entre deux simulations et le Delay INIFINITE en cas d'inactivité


    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
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    unit UnTHREADTstEv;
     
    interface
     
    uses
      System.Classes, System.SysUTILS, System.SyncObjs;
     
    type
      ThreadTstEvent = class(TThread)
      private
        FActive: Boolean;
        FEvent: TEvent;
        procedure SetActive(Value: Boolean);
      protected
        procedure Execute; override;
        procedure TerminatedSet(); override;
      public
        constructor Create();  
        destructor Destroy(); override; 
     
        property Active: Boolean read FActive write SetActive;
      end;
     
    implementation
     
    Uses UnTestThreadEvent;
     
    { ThreadTstEvent }
     
    //------------------------------------------------------------------------------
    constructor ThreadTstEvent.Create(); 
    begin
      inherited Create(); // Le thread n'est lancé qu'au moment du AfterConstruction, cela laisse donc la possibilité de configurer notre objet ici
     
      FEvent := TEvent.Create(False); 
    end;  
     
    //------------------------------------------------------------------------------
    destructor ThreadTstEvent.Destroy(); override; 
    begin
      Terminate();
      WaitFor();
     
      FreeAndNil(FEvent);  
     
      inherited Destroy();
    end;  
     
    //------------------------------------------------------------------------------
    procedure ThreadTstEvent.Execute();
    var
      Delay: Cardinal;
    begin; 
      Delay := INFINITE;
     
      FSimulation := False;
      while not Terminated do
      begin
        case FEvent.WaitFor(Delay) of
            wrTimeout: FSimulation := True;
            wrSignaled: FSimulation := FActive;
        end;    
     
        if not Terminated then
        begin
          if FSimulation then
          begin
            Synchronize (
              procedure
              begin
                Form1.Memo1.Lines.Add(IntToStr(c1) + ' ligne(s) Thread second');
                Form1.Memo1.GoToTextEnd;
                Inc(C1); // InterlockIncrement/AtomicIncrement permettrait de sortir du Synchronize !
              end);
            Delay := 500;      // en fait 500 - Durée du traitement sinon ça se décalera d'autant à chaque itération
          end
          else
          begin
            Synchronize (
              procedure
              begin
                Form1.Memo1.Lines.Append(' Thread en attente');
                Form1.Memo1.GoToTextEnd;
              end);
              Delay := INFINITE;
          end;
        end;    
      end;
    end;
     
    //------------------------------------------------------------------------------
    procedure ThreadTstEvent.TerminatedSet();
    begin
      inherited TerminatedSet();
     
      if Assigned(FEvent) then
        FEvent.SetEvent();
    end;
     
     
    //------------------------------------------------------------------------------
    procedure ThreadTstEvent.SetActive(Value: Boolean);
    begin
      if FActive <> Value then
      begin
        FActive := Value;   // Les plus parano utiliserait une Section Critique ou un InterlockedCompareExchange 
     
        if Assigned(FEvent) then
          FEvent.SetEvent();
      end;
    end;



    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
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    unit UnTestThreadEvent;
     
    interface
     
    uses
      System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
      FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Memo.Types,
      FMX.StdCtrls, FMX.Controls.Presentation, FMX.ScrollBox, FMX.Memo, UnTHREADTstEv,
      System.SyncObjs;
     
    type
      TForm1 = class(TForm)
        Memo1: TMemo;                   // memo du thread secondaire
        BtSuspend: TButton;
        BtResume: TButton;
        Memo2: TMemo;                    // memo du thread principal
        BtStart: TButton;
        BtQuit: TButton;
        Timer1: TTimer;
        procedure BtStartClick(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure BtQuitClick(Sender: TObject);
        procedure Timer1Timer(Sender: TObject);
        procedure BtSuspendClick(Sender: TObject);
        procedure BtResumeClick(Sender: TObject);
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
     
    var
      Form1: TForm1;
      c1, c2 : integer;
      MThr :  ThreadTstEvent;
     
      Prempass : boolean = true;
     
    implementation
     
    {$R *.fmx}
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
     C1 := 0;
     C2 := 0;
     prempass := true;
     
     MThr := ThreadTstEvent.Create(False); 
     
    end;
     
    procedure TForm1.BtStartClick(Sender: TObject);
    var i : integer;
    begin
      c2 := 0;
      Timer1.Enabled := true;                    // process du thread principal
    end;
     
     
    procedure TForm1.BtResumeClick(Sender: TObject);   //simule RESUME
    begin
      MThr.Active := True; 
    end;
     
     
    procedure TForm1.BtSuspendClick(Sender: TObject);  // simule SUSPEND
    begin
      MThr.Active := False;
    end;
     
     
     
    procedure TForm1.Timer1Timer(Sender: TObject);
    begin
      Memo2.Lines.Add (IntToStr (c2) + ' ligne(s) thread principal ');
      Memo2.GoToTextEnd;
      Inc (c2);
    end;
     
     
     
    procedure TForm1.BtQuitClick(Sender: TObject);
    begin
      FreeAndNil(MThr);
      Close;
    end;
     
    end.
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 933
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 933
    Par défaut
    J'aurais tendance à ne faire appel qu'aux APIs (l'objet TEvent n'apportant pas grand chose) et à dupliquer le handle afin de ne pas utiliser WaitFor bloquant
    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
    type
      TMyThread = class(TThread)
      private
        Event :THandle;
      protected
        procedure Execute; override;
      public
        constructor Create(aEvent :THandle);
      end;
     
      TForm1 = class(TForm)
        Button1: TButton;
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure Button1Click(Sender: TObject);
      private
        Event :THandle;
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
    uses System.SyncObjs;
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      Event := CreateEvent(nil, TRUE, FALSE, '');
      TMyThread.Create(Event);
    end;
     
    procedure TForm1.FormDestroy(Sender: TObject);
    begin
      CloseHandle(Event);
    end;
     
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      SetEvent(Event);
    end;
     
    { TMyThread }
     
    constructor TMyThread.Create(aEvent: THandle);
    begin
      inherited Create;
      DuplicateHandle(GetCurrentProcess, aEvent, GetCurrentProcess, @Event, 0, FALSE, DUPLICATE_SAME_ACCESS);
    end;
     
    procedure TMyThread.Execute;
    begin
      WaitForSingleObject(Event, INFINITE);
     
      CloseHandle(Event);
    end;

  6. #6
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 086
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 086
    Par défaut
    Le Projet est mentionné en FMX donc faudrait prendre en compte une éventuelle compatibilité multi-OS.

    TEvent m'a toujours convenu et je préfère le masquer dans le TThread que j'utilise comme un objet métier, de l'extérieur le que possible, c'est pas important que l'on prenne en compte que l'objet est un thread car toutes les I\O sont protégées par le thread lui même via Accesseurs ou Méthodes, toujours dans l'idée que le code soit le plus faiblement couplé.
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  7. #7
    Membre averti
    Homme Profil pro
    Retraité
    Inscrit en
    Août 2018
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Août 2018
    Messages : 14
    Par défaut
    Un grand merci à vous deux ShaiLeTroll et Andnotor. Je vais examiner vos retours attentivement . J'ai bien compris le mécanisme du TEvent qui doit être un membre privé du thread secondaire . Merci pour le code !
    C'est vrai que mon exemple était ballot puisque dans un souci de simplification je n'avais laissé comme travail pour le thread secondaire que le contenu de la fonction Synchronize. Dans mon projet réel, Synchronize devait afficher chaque phrase dans le Tmemo et le thread s'occuper de la transmission conditionnelle en RS232 et /ou en Wifi.

    Bon là je me plonge dans vos remarques, une à la fois !

  8. #8
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 933
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 933
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Le Projet est mentionné en FMX
    Ah oui


    Sinon tu peux simplifier un peu. Terminate est déjà appelé par Destroy, donc deux fois dans ton cas ce qui t'oblige à tester la validité du event. En le libérant après inherited Destroy tu n'as plus cette contrainte.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    destructor TMyThread.Destroy;
    begin
      inherited;
      FEvent.Free;
    end;
     
    procedure TMyThread.TerminatedSet;
    begin
      inherited;
      FEvent.SetEvent;
      WaitFor;
    end;

Discussions similaires

  1. TThread resume et suspend
    Par Pocus dans le forum Langage
    Réponses: 4
    Dernier message: 16/12/2011, 07h59
  2. [Requete] Erreur de syntaxe, mais encore ?
    Par soforever dans le forum Requêtes et SQL.
    Réponses: 2
    Dernier message: 30/04/2007, 13h34
  3. 4 inodes de libre.. mais encore 2.2gb de libre
    Par mariogarcia dans le forum Administration système
    Réponses: 4
    Dernier message: 23/02/2007, 11h22
  4. [MATHS] Minterm / Maxterm, mais encore?
    Par cladsam dans le forum Mathématiques
    Réponses: 4
    Dernier message: 20/09/2006, 09h21
  5. Réponses: 4
    Dernier message: 06/07/2006, 20h36

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo