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

Delphi Discussion :

Firemonkey : utilisation des threads


Sujet :

Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Programmeur
    Inscrit en
    Octobre 2015
    Messages
    80
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Programmeur
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Octobre 2015
    Messages : 80
    Par défaut Firemonkey : utilisation des threads
    Bonjour,

    j'aimerais m'ôter quelques doutes. Ma fenêtre principale ouvre un thread
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    {Docs
      - http://edn.embarcadero.com/article/25707 [base]}
    procedure TfMain.FormShow(Sender: TObject);
    begin
      workerThread := TWorkerThread.Create(false);
    end;
    et le thread simplifié
    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
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    unit uWorkerThread;
     
    interface
     
    uses
      System.Classes, FMX.Dialogs,
      {Indy}
      IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
      IdExplicitTLSClientServerBase, IdFTP,
      {FireDac}
      FireDAC.Stan.Intf,
      FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf,
      FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys,
      FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf, FireDAC.DApt,
      FireDAC.FMXUI.Wait, FireDAC.Comp.UI, FireDAC.Comp.Client, Data.DB,
      FireDAC.Comp.DataSet,
      {Mine}
      uStatics;
     
    type
      TWorkerThread = class(TThread)
        IdFTP : TIdFTP;
        mySQLconn: TFDConnection;
        mySQLquery: TFDQuery;
        mySQLtrans: TFDTransaction;
        mySQLxWaitCursor: TFDGUIxWaitCursor;
     {  procedure IdFTPStatus(ASender: TObject; const AStatus: TIdStatus;
        const AStatusText: string);
        procedure IdFTPWorkBegin(ASender: TObject; AWorkMode: TWorkMode;
        AWorkCountMax: Int64);
        procedure IdFTPWork(ASender: TObject; AWorkMode: TWorkMode;
        AWorkCount: Int64);
        procedure IdFTPWorkEnd(ASender: TObject; AWorkMode: TWorkMode); }
     
      private
        { Déclarations privées }
     
      protected
        procedure Execute; override;
     
      public
        procedure UpdateUI;
        procedure FinishUI;
        procedure MessToUI;
      end;
     
    var
       i: integer;
       sErr: string;
     
    implementation
     
    uses SysUtils, wMain;
     
    { TWorkerThread }
     
    procedure TWorkerThread.Execute;
    begin
      mySQLconn        := TFDConnection.Create(nil);
      mySQLquery       := TFDQuery.Create(nil);
      mySQLtrans       := TFDTransaction.Create(nil);
      mySQLxWaitCursor := TFDGUIxWaitCursor.Create(nil);
     
      with mySQLconn do
        begin
          if Connected then Connected := False;
          DriverName := 'MySQL';
          Transaction := mySQLtrans;
          with Params do
            begin
              Add('Server='   + csLicHost);
              Add('Database=' + csLicBase);
              Add('User_Name='+ csLicUser);
              Add('Password=' + csLicPass);
            end;
        end;
      with mySQLtrans do
        Connection := mySQLconn;
      with mySQLquery do
        begin
          Connection   := mySQLconn;
          Transaction  := mySQLtrans;
        end;
     
      with mySQLconn do
        try
          Connected := True;
          sErr := 'Connecté';
        except
          sErr := 'Connexion impossible';
        end;
      Synchronize(MessToUI);
     
      for i := 1 to 100 do
        begin
          Synchronize(UpdateUI);
        end;
     
     
      with mySQLconn do
        if Connected then Connected := false;
     
      mySQLxWaitCursor.Free;
      mySQLtrans.Free;
      mySQLquery.Free;
      mySQLconn.Free;
     
      FreeOnTerminate := true;
      Synchronize(FinishUI);
    end;
     
    procedure TWorkerThread.UpdateUI;
    begin
      fmain.Gauge.Value := i;
    end;
     
    procedure TWorkerThread.MessToUI;
    begin
      showmessage(sErr);
    end;
     
    procedure TWorkerThread.FinishUI;
    begin
      showmessage('Close');
      fMain.Close;
    end;
     
    end.
    Ce thread se connecte à une base MySQL et opère un chargement FTP (par Indy 10).
    Alors première surprise, si les composants FireDac sont placés sur la TFmain, cela semble fonctionner. Enfin, il est clair que je récupère la valeur cherchée avec la requête.
    1. Or il est précisé que la connexion doit être isolée. Ce connecteur ne servant qu'une fois et comme il est quand même plus pratique de définir les paramètres avec l'IO et surtout de vérifier les paramètres par défaut qu'il est difficile de connaître lors d'une création dynamique, j'hésite un peu.
    2. D'autant que si je définis dynamiquement la connexion dans le thread, la présence du TFDGUIxWaitCursor ne semble pas nécessaire alors qu'elle l'est sur la Tfmain. Nouvelle incertitude. Obligatoire dans le thread ou non ?
    3. Le FreeOnTerminate := true; du thread détruit-il tous les objets qu'il contient ? Je suppose que oui. Autrement dit, les mySQLxWaitCursor.Free; mySQLtrans.Free; mySQLquery.Free; mySQLconn.Free; sont-ils nécessaires ?
    4. J'ai les mêmes questions pour le composant Indy avec en plus la gestion des
      • procedure IdFTP1Work(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
      • procedure IdFTP1WorkBegin(ASender: TObject; AWorkMode: TWorkMode; AWorkCountMax: Int64);
      • procedure IdFTP1WorkEnd(ASender: TObject; AWorkMode: TWorkMode);
      Est-il préférable de créer le composant dynamiquement dans le thread et d'incorporer dans les méthodes ci-dessus des synchronize ou d'utiliser dans le thread un composant idFTP1 de Tfmain ? Les 2 options semblant fonctionner.

    Beaucoup de questions (compilées cette semaine) en un seule mais toutes finalement relatives à l'utilisation de Thread.

    Merci.Zac.

  2. #2
    Expert confirmé
    Avatar de Ph. B.
    Homme Profil pro
    Freelance
    Inscrit en
    Avril 2002
    Messages
    1 786
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2002
    Messages : 1 786
    Par défaut
    Bonjour,
    Citation Envoyé par Zacheus Voir le message
    j'aimerais m'ôter quelques doutes. Ma fenêtre principale ouvre un thread
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    {Docs
      - http://edn.embarcadero.com/article/25707 [base]}
    procedure TfMain.FormShow(Sender: TObject);
    begin
      workerThread := TWorkerThread.Create(false);
    end;
    Attention, si pour une raison ou une autre votre fenêtre est masquée puis réaffichée, le thread va être relancé autant de fois que la méthode FormShow va être appelée...

    Citation Envoyé par Zacheus Voir le message
    Ce thread se connecte à une base MySQL et opère un chargement FTP (par Indy 10).
    Alors première surprise, si les composants FireDac sont placés sur la TFmain, cela semble fonctionner. Enfin, il est clair que je récupère la valeur cherchée avec la requête.
    Possible si votre thread est le seul à intervenir avec...

    Citation Envoyé par Zacheus Voir le message
    Or il est précisé que la connexion doit être isolée. Ce connecteur ne servant qu'une fois et comme il est quand même plus pratique de définir les paramètres avec l'IO et surtout de vérifier les paramètres par défaut qu'il est difficile de connaître lors d'une création dynamique, j'hésite un peu.
    Ce n'est pas parce que c'est plus pratique de définir des paramètres depuis l'EDI plutôt que par code que cela est préférable...

    Citation Envoyé par Zacheus Voir le message
    D'autant que si je définis dynamiquement la connexion dans le thread, la présence du TFDGUIxWaitCursor ne semble pas nécessaire alors qu'elle l'est sur la Tfmain. Nouvelle incertitude. Obligatoire dans le thread ou non ?
    Le composant n'est pas obligatoire du moment que l'unité ad-hoc est présente dans la clause uses : FireDAC.VCLUI.Wait, FireDAC.FMXUI.Wait, FireDAC.ConsoleUI.Wait suivant le type d'application développée.
    cf. l'aide de Delphi...

    Citation Envoyé par Zacheus Voir le message
    Le FreeOnTerminate := true; du thread détruit-il tous les objets qu'il contient ? Je suppose que oui. Autrement dit, les mySQLxWaitCursor.Free; mySQLtrans.Free; mySQLquery.Free; mySQLconn.Free; sont-ils nécessaires ?
    NON ! L'objet TWorkerThread est détruit une fois le thread sous jacent terminé, pas les objets qu'il contient.
    D'autre part, les objets que vous avez créés ne sont rattachés à aucun propriétaire chargé de leur destruction.
    Donc OUI ! Il vous faut explicitement les libérer et ce dans la méthode associée à l'événement OnTerminate du thread.

    Citation Envoyé par Zacheus Voir le message
    J'ai les mêmes questions pour le composant Indy
    J'ai la même réponse...

    Citation Envoyé par Zacheus Voir le message
    Est-il préférable de créer le composant dynamiquement dans le thread et d'incorporer dans les méthodes ci-dessus des synchronize ou d'utiliser dans le thread un composant idFTP1 de Tfmain ? Les 2 options semblant fonctionner.
    Ces composants sont dédiés au thread, autant les créer dynamiquement et les libérer dans celui-ci...
    Cela évite de surcroit de tout mélanger et une réutilisation aux conséquences variables mais fâcheuses...

  3. #3
    Membre confirmé
    Homme Profil pro
    Programmeur
    Inscrit en
    Octobre 2015
    Messages
    80
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Programmeur
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Octobre 2015
    Messages : 80
    Par défaut
    Bonjour,

    OK. Merci pour ces réponses.

    La Form ne s'ouvre qu'une fois en effet et elle est détruite immédiatement après usage. J'ai choisi de placer tous les composants dans le thread. Pour être plus précis, la destruction de la form ne détruira pas non plus les objets du thread si on ne les libère pas par le code, mais la fermeture du programme, on peut supposer que si.

    Autre précision, le OnTerminate est-il appelé à tous les coups c'est à dire même si par exemple, on ferme la fenêtre en cours de thread.execute ?

    Autre problème : Utiliser des MessageDlg dans un thread est-il envisageable ? Sachant que cela semble fonctionnel.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    if (eErr = eSQLerr) then
      begin
        DlgResult := MessageDlg( 'Votre choix ?',
                           System.UITypes.TMsgDlgType.mtInformation,
                           [ System.UITypes.TMsgDlgBtn.mbYes,
                             System.UITypes.TMsgDlgBtn.mbNo
                           ],0);
       if DlgResult = mrYES then aRes := 2 else aRes := 0;
       Synchronize(UI_FinalResult);
     end;
    Le UI_FinalResult envoie aRes vers une variable publique de la Form. Cette valeur sera traitée dans le code de procedure TfMain.FormClose et déterminera son comportement : simple fermeture, lancement d'un autre programme. FormClose est appelée par un Ui_Finish par le thread.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     FreeOnTerminate := true;
     Synchronize(FinishUI);
    J'ai bien saisi qu'il était recommandé de modifier l'interface de la Form par des synchronize. Mais dans le cas présent, le MessageDlg n'appartient pas à la Form. Evidemment en attente du choix le thread est bloqué.

    Enfin sur le synchronize, je suppose qu'il est impossible de passer une variable avec le nom de la méthode.

    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
    procedure TWorkerThread.IdFTPWork(ASender: TObject; AWorkMode: TWorkMode;
      AWorkCount: Int64);
    begin
      if AWorkMode = wmRead then 
        begin
          iGauge := Round(AWorkCount / nGaugemax *100);
          synchronize(UI_GaugeUpdate);
       end;
    end;
     
    procedure TWorkerThread.UI_GaugeUpdate;
    begin
      with fMain.Gauge do
        Value := iGauge;
    end;
    Il semble que l'on soit obligé de passer par une variable du TWorkerThread, ici iGauge. Un synchronize(UI_GaugeUpdate, Value); serait plus simple.

    Merci. Zac.

Discussions similaires

  1. Avis sur la bonne utilisation des Threads
    Par Pitivier dans le forum Général Java
    Réponses: 8
    Dernier message: 28/11/2006, 20h07
  2. connexion socket utilisant des threads
    Par alceste dans le forum C++
    Réponses: 16
    Dernier message: 14/10/2006, 12h00
  3. [Débutant]Utilisation des Threads
    Par maniolo dans le forum Débuter avec Java
    Réponses: 19
    Dernier message: 10/07/2006, 11h31
  4. Utilisation des threads
    Par Valinor dans le forum Linux
    Réponses: 2
    Dernier message: 30/11/2005, 16h41
  5. Utilisations des Threads
    Par phoenix440 dans le forum Réseau
    Réponses: 15
    Dernier message: 21/08/2005, 17h19

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