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 :

Première tentative de multithread, ouch !


Sujet :

Delphi

  1. #21
    Membre régulier
    Homme Profil pro
    Inscrit en
    Août 2006
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Août 2006
    Messages : 108
    Points : 82
    Points
    82
    Par défaut
    Salut Hohorga,

    Merci pour ta réponse.
    Oui il y a pas mal d'erreurs et/ou d'incohérence dans ce code.

    Je continu d'avancer dessus, je n'abandonne pas

    Un truc que j'avais complètement zappé, c'est l'utilisation d'une ThreadList (ou TList) afin d'avoir un index des threads actifs... (Comme expliqué plus haut par Shai)
    Donc apparemment mes threads sont lancés dans le vide.

    Je tiens ce topic informé de mon avancement.

    Beny

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 698
    Points : 13 137
    Points
    13 137
    Par défaut
    Je répond un peu en vrac, désolé

    @hohorga
    Oui, il faut affecter Thread après la boucle. La logique (à l'édition) voudrait que Thread vaille SpinEdit1.Value, mais ce n'est pas le cas (après compilation). Il vaudra SpinEdit1.Value +1. Le code compilé donne un inc suivi d'un plus grand que. En fait la variable de boucle n'est cohérente que dans la boucle elle-même !

    Sinon, oui ces Synchronize(Sync) et Synchronize(LastUpdate) se pilent dessus. Imagine simplement que le 1er Thread à avoir terminé son job se lance dans une boucle infini dans la tâche principale. Les 199 autres s'en verront forcément pénalisé, bloquerons sur leurs propres Synchronize puisqu'il souhaiteraient aussi avoir accès à la tâche principale. Quand il n'en reste plus qu'un (si vraiment ça arrive), il y en a 199 qui jouent des coudes et consomment du temps processeur pour rien

    Tu as un contrôle qui défini Work=FALSE, c'est à ce moment là que Synchronize(LastUpdate) doit être appelé; une seule fois !

    Sinon, attention aux construction/destruction. Si tu presses 5 fois sur Button1, tu auras 1000 TThread, 1000 TIdHTTP et autant de StringList, de sections critiques que d'appui sur le bouton

    On peut facilement imaginer que chaque thread passe sont temps à attendre une réponse "internet" (et ainsi laisser du temps aux autres), mais 200 threads, ça me paraît beaucoup. Essaye déjà avec 10 ou 20... Ça dépendra en fait beaucoup de ta connexion internet (charge) et du serveur cible (S'il n'accepte que 10 connexions simultanées, je te laisse imaginé )

  3. #23
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 460
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    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 : 13 460
    Points : 24 874
    Points
    24 874
    Par défaut
    Citation Envoyé par benymypony Voir le message
    Un truc que j'avais complètement zappé, c'est l'utilisation d'une ThreadList (ou TList) afin d'avoir un index des threads actifs... (Comme expliqué plus haut par Shai)
    Tu noteras que ma dernière version n'utilise pas de ThreadList mais un Evènement !
    Pour la ThreadList, il faut faire des PUSH \ POP comme dans une FIFO, dans ton cas, on peut s'en sortir plus simplement !
    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

  4. #24
    Membre régulier
    Homme Profil pro
    Inscrit en
    Août 2006
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Août 2006
    Messages : 108
    Points : 82
    Points
    82
    Par défaut
    Merci Shail, Paul, Andnotor et Hohorga pour votre aide précieuse !

    Je continu d'avancer sur ce sujet.
    J'ai fais pas mal d’expérimentations depuis le début de ce topic et pense pouvoir considérer ce sujet comme résolu.

    J'ai repris mon code depuis zéro plusieurs fois, ça m'a beaucoup aidé.
    Le multithread fonctionne très bien.
    Les seuls problèmes que j'ai viennent plutôt de Indy (qui est bloquant...) mais qui semblent pouvoir être fixés via une ThreadList ou un Evènement (comme indiqué par Shai dans son dernier post).

    Sinon j'ai trouvé un exemple vidéo de la création d'une application simple en multithread et utilisant Indy, je suis sur que ça pourra en intéresser certains (les fichiers sources sont disponible) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    http://avtuh.ru/2010/10/10/delphi-videourok-mnogopotochnost-i-sinxronizaciya.html
    Bon, c'est en Russe et il n'aborde pas l'étape de "termination", mais c'est toujours ça.

    Merci encore à vous tous

    Beny

  5. #25
    Membre actif Avatar de remixtech
    Profil pro
    Enseignant
    Inscrit en
    Février 2003
    Messages
    272
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Février 2003
    Messages : 272
    Points : 214
    Points
    214
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Perso, je ne pratique pas Synchronize car j'ai plus souvent de la synchro entre thread secondaire et rarement avec le principal !
    Mais pour le cas présent, c'est plus simple !
    Merci pour cette question.

    Quelques questions :

    • Sans synchronize pas question d'avoir accès au thread principal depuis un thread secondaire ?
    • Le passage/recupération d'informations ne posent jamais de problème entre deux threads secondaires? Pas de synchronize entre eux?
    • Le thread principal peut-il accéder aux propriétés d'un thread secondaire pour récupérer des informations sans synchroniser ?
    • J'utilise abusivement synchronize pour passer au thread principal des informations (progression, status...), mais ce ne sont pas des actions "bloquantes" du coup on s'en fiche ? Y'a t'il un autre moyen ?


    Merci beaucoup

  6. #26
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 460
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    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 : 13 460
    Points : 24 874
    Points
    24 874
    Par défaut
    Citation Envoyé par remixtech Voir le message
    [*]Sans synchronize pas question d'avoir accès au thread principal depuis un thread secondaire ?
    Je le fais indirectement, si un thread manipule de l'IHM, il va mettre des infos dans une TThreadList, dans OnIdle (ou un Timer) dans le Main va lire la ThreadList pour afficher les infos.
    J'utilise aussi PostThreadMessage ou un Synchronize qui fait un PostMessage
    Pour bloquer le thread appelant le moins longtemps que possible


    Citation Envoyé par remixtech Voir le message
    [*]Le passage/recupération d'informations ne posent jamais de problème entre deux threads secondaires? Pas de synchronize entre eux?
    TCriticalSection, TList, TThreadList, Event... un thread ne peut pas écrire si un autre thread est en train de lire et vice-versa, si tu modifie une valeur en cours de route, ça peut fausser le comportement, si c'est une liste géré en FIFO c'est violation d'accès assuré si tu ne protèges pas la mémoire !

    Maintenant le Thread fourni des fonctions Synchronize et Queue inter-thread et non plus qu'avec le Main !
    Je n'ai pas encore testé cela !

    Citation Envoyé par remixtech Voir le message
    [*]Le thread principal peut-il accéder aux propriétés d'un thread secondaire pour récupérer des informations sans synchroniser ?
    A ses risques et péril, un entier en lecture, pas de soucis, une Liste, si tu parcours un tableau, pendant ce temps, le thread fait un Add ou un Delete qui provoque une réallocation de la liste, ça doit pas être très bon

    Citation Envoyé par remixtech Voir le message
    [*]J'utilise abusivement synchronize pour passer au thread principal des informations (progression, status...), mais ce ne sont pas des actions "bloquantes" du coup on s'en fiche ? Y'a t'il un autre moyen ?
    En général, je préfère utiliser des Evènements, le thread expose des Events indiquant la progression ou des changement d'état, celui qui fourni les gestionnaires des évènements se débrouillent avec sachant que mes events sont lancés sans synchronise !

    le thread ne doit pas connaître l'extérieur !
    plus le couplage des objets est faible mieux c'est !

    le même objet pouvnat être ainsi utiliser par différente forme du programme
    une version GUI de l'application, le thread est lancé manuellement avec progression détaillée
    une version console ou GUI simplifié pour TaskManager, le thread lancé manuellement et affiche des ECHO ou une progression minimale
    une version Service Windows, le thread lancé automatiquement, pas de progression mais juste un log pour le démarrage, l'arrêt ou la gestion des erreurs !
    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. #27
    Membre actif Avatar de remixtech
    Profil pro
    Enseignant
    Inscrit en
    Février 2003
    Messages
    272
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Février 2003
    Messages : 272
    Points : 214
    Points
    214
    Par défaut
    Merci beaucoup pour tes réponses. C'est bien ce qui me semblait.

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 698
    Points : 13 137
    Points
    13 137
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    J...ou un Synchronize qui fait un PostMessage Pour bloquer le thread appelant le moins longtemps que possible
    Tu pourrais ne pas le bloquer du tout en supprimant le synchronize

    Sinon, la mise à jour d'une barre de progression est typiquement:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    PostMessage(Wnd, Message, Position, Max);

  9. #29
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 460
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    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 : 13 460
    Points : 24 874
    Points
    24 874
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    Tu pourrais ne pas le bloquer du tout en supprimant le synchronize
    Oui, a y réfléchir, j'ai bien utiliser PostMessage depuis un autre processus, alors depuis un thread il ne devrait pas y avoir de soucis !

    Je fais beaucoup d'appli "serveur", sans IHM, je ne pose pas la question de l'affichage
    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

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 698
    Points : 13 137
    Points
    13 137
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Je fais beaucoup d'appli "serveur", sans IHM, je ne pose pas la question de l'affichage
    L'affichage n'est souvent qu'un prétexte mais la notion réelle est le Handle et la communication entre threads ou processus. Il n'y a pas besoin de fenêtre au sens visuel (window) pour cela

  11. #31
    Membre actif Avatar de remixtech
    Profil pro
    Enseignant
    Inscrit en
    Février 2003
    Messages
    272
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Février 2003
    Messages : 272
    Points : 214
    Points
    214
    Par défaut
    Vous qui êtes balèze sur le sujet, je me permet de vous poser une autre question.

    Si j'ai un objet en mémoire (TObject) qui :
    - Peut être lu par le thread principal
    - Peut être écrit par deux threads secondaires

    être thread safe, c'est juste arrivé à mettre en place les moyens que les threads secondaires n'écrivent pas en même temps et que la lecture dans le thread principal ne se fasse pas en même temps ?

    Du coup on utilise des sections critiques ou des mutex (ou sémaphore, ou évènement...) pour être certain qu'à l'instant T, les autres n'accèdent pas à la ressource ?

    Autre question de manière pragmatique pour faire patienter, on fait tourner à vide le thread en boucle en attendant la récupération du mutex ?

    ---

    Perso, je n'en ai pas besoin, j'utilise TThread avec synchronize en abondance.

    Mais je crois que synchronize n'est pas aussi performant qu'une gestion plus fine avec les mutex et compagnie, c'est une espèce de section critique entre le thread principal et secondaire c'est ça ?

    ---

    Note intéressante : Le Generic TThreadedQueue a été corrigé et est enfin pleinement fonctionnel dans XE2 Up 4 !

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 698
    Points : 13 137
    Points
    13 137
    Par défaut
    Citation Envoyé par remixtech Voir le message
    être thread safe, c'est juste arrivé à mettre en place les moyens que les threads secondaires n'écrivent pas en même temps et que la lecture dans le thread principal ne se fasse pas en même temps ?
    C'est ça sans tenir compte de la lecture ou écriture, threads principal ou secondaires. En gros c'est chacun son tour ou en tout les cas, on ne lit plus si quelque'un écrit.

    Citation Envoyé par remixtech Voir le message
    Autre question de manière pragmatique pour faire patienter, on fait tourner à vide le thread en boucle en attendant la récupération du mutex ?
    Non, on le met carrément en attente. Il ne consomme plus de temps CPU.
    Mais mieux vaut le réveiller de temps en temps (time-out) juste histoire de tester si la sortie à été demandée (Terminated); un thread en attente empêche la fin du processus !

    Citation Envoyé par remixtech Voir le message
    Mais je crois que synchronize n'est pas aussi performant qu'une gestion plus fine avec les mutex et compagnie, c'est une espèce de section critique entre le thread principal et secondaire c'est ça ?
    Par analogie, mais il ne s'agit plus uniquement de la validité des données, on force purement et simplement du code à s’exécuter dans la tâche principale (accès à des données partagées ou pas)

  13. #33
    Membre régulier
    Homme Profil pro
    Inscrit en
    Août 2006
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Août 2006
    Messages : 108
    Points : 82
    Points
    82
    Par défaut
    Vous essayez de me semer, c'est ça ?

    Beny

  14. #34
    Membre régulier
    Homme Profil pro
    Inscrit en
    Août 2006
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Août 2006
    Messages : 108
    Points : 82
    Points
    82
    Par défaut
    Bonsoir à tous,

    Après avoir tester et bricoler beaucoup de code, je suis enfin parvenu à mes fins
    Merci encore pour votre aide et votre patience à tous.

    Finalement ce n'est pas si compliquer...

    Pour aider ceux qui souhaiterais faire la même chose, voici en fichier joint le code-source de mon application d'exemple.

    Aussi, voici ci-dessous le code-source entièrement commenté.
    J'ai essayé d'être le plus clair et le plus précis possible.

    Bon le multithread ça reste encore récent pour moi, donc si un vétéran passe par là et y voit des erreurs de code ou des commentaires mal formulés, n'hésitez pas.

    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
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    {
      Demo Multithread
     
      Application réalisée dans le but de montrer comment réaliser
      du multithread avec Delphi (version XE2 dans ce cas précis).
     
      Ici, le multithread servira à "découper" une longue procédure (boucle)
      en multiple opérations simultanées.
      Un ListBox contient plusieurs URLs, et nous souhaitons savoir laquelle
      de ces URLs contient une expression précise.
     
      L'opération se présente ainsi : on prend une URL ; on récupère son contenu
      par GET via Indy que l'on affecte à une StringList ; on vérifie
      si l'expression choisie est présente dans la StringList ;
      et ensuite nous attribuons un résultat positif ou négatif à l'opération.
     
      Le multithread est encore tout frais pour moi, ce code est probablement
      optimisable et/ou comporte quelques erreurs :)
     
      Les commentaires sont à lire dans l'ordre d'exécution du programme.
      Chaque commentaire concerne le code du dessous.
     
      Beny (Delphi forum, Developpez.com)
    }
     
    unit Main;
     
    interface
     
    uses
      // Pour synchroniser les threads, vous aurrez besoin de "System.SyncObjs".
      // Pour utiliser Indy (GET), vous aurez besoin de "IdHTTP".
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
      System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
      Vcl.StdCtrls, Vcl.Samples.Spin, System.SyncObjs, IdHTTP;
     
    type
      TFormMain = class(TForm)
        ListBox: TListBox;
        LabelThreads: TLabel;
        SpinEditThreads: TSpinEdit;
        ButtonStart: TButton;
        ButtonStop: TButton;
        LabelTitre: TLabel;
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
        procedure FormCreate(Sender: TObject);
        procedure ButtonStartClick(Sender: TObject);
        procedure ButtonStopClick(Sender: TObject);
      private
      public
      end;
     
      // La CLASS de notre thread.
      TDemoThread = class(TThread)
        // Dans PRIVATE nous plaçons les variables qui seront modifiées
        // par les différents threads simultanément, et qui pourront communiquer
        // entre le thread et les synchronisations sans interférences.
      private
        URL: String;
        LigneActive, Resultat: Integer;
      protected
        // La procédure principal.
        procedure Execute; override;
      public
        // Pour la synchronisation de fin de procédure.
        procedure Finish;
        // Pour la synchronisation de début de procédure.
        procedure Initialize;
        // Ce qui lancera chaque thread.
        constructor Create(CreateSuspended: Boolean);
      end;
     
    var
      FormMain: TFormMain;
      CS: TCriticalSection; // La CriticalSection (voir FormCreate plus bas).
      SL: TStringList; // La StringList (voir FormCreate plus bas).
      Threads, Ligne: Integer; // Nous y reviendrons plus tard...
      Work: Boolean; // Quand l'opération commence, WORK passe à TRUE.
     
    implementation
     
    {$R *.dfm}
     
    // Le thread est crée ici.
    constructor TDemoThread.Create(CreateSuspended: Boolean);
    begin
      inherited Create(CreateSuspended);
    end;
     
    // Voici le code principal du thread.
    // Vous verrez qu'il n'interagit jamais avec l'interface, cette étape sera
    // gérée par les synchronisations que nous verrons plus bas.
    procedure TDemoThread.Execute;
    var
      Raw: TStringList; // StringList temporaire pour stocker le code-source.
      HTTP: TIdHTTP; // On déclare ici le composant HTTP de Indy.
    begin
      // Si "WORK=TRUE" l'opération continue normalement...
      while Work do
      begin
        // Ici nous allons vérifier s'il reste des URLs à traiter.
        // Nous allons utiliser ici la CriticalSection afin que cette opération
        // ne soit pas effectuée simultanément par plusieurs threads ;
        // ce qui fausserait le résultat.
     
        // Nous entrons en section critique...
        CS.Enter;
     
        // Nous incrémentons de "+1" la position actuelle dans la StringList
        // contenant les URLs à traiter.
        // Pour rappel, LIGNE est un Integer.
        Inc(Ligne);
     
        // Si la position actuelle est inférieur à la dernière ligne
        // de la StringList, alors nous allons pouvoir traiter cette URL ;
        if Ligne < SL.Count then
          LigneActive := Ligne
        else
          // Sinon, on en déduit qu'il n'y a plus d'URLs à traiter.
          Work := False;
     
        // Nous quittons la section critique.
        CS.Leave;
     
        // Si la vérification effectuée ci-dessus donne un résultat positif
        // alors nous pouvons procéder à l'opération.
        if Work then
        begin
          // On récupère l'URL en cours et on l'affecte à un simple String.
          // Ce n'est pas essentiel mais cela limite les connexions entre
          // la StringList contenant les URLs et les threads.
          // Important : comme cette variable sera utilisée dans le
          // thread principal (ici) et dans les SYNCHRONIZE, il est nécessaire
          // de déclarer "URL:STRING" dans PRIVATE de la CLASS "TDemoThread".
          URL := SL[LigneActive];
     
          // On intéragit avec l'interface afin que l'utilisateur sache
          // ce qu'il se passe et où nous en sommes.
          Synchronize(Initialize);
     
          // On crée la StringList temporaire.
          Raw := TStringList.Create;
     
          // On crée le composant HTTP et on le paramètre vite-fait, bien-fait.
          HTTP := TIdHTTP.Create;
          HTTP.HandleRedirects := True;
          HTTP.ReadTimeout := 15000;
          HTTP.ConnectTimeout := 15000;
     
          // Dans un TRY/EXCEPT on fait un GET pour récupérer le code source
          // de l'URL, que l'on va affecter à la StringList créée précédemment.
          try
            Raw.Text := HTTP.Get(URL);
          except
            // En cas d'erreur, pas de panique (EXCEPT peut rester vide).
            Application.ProcessMessages;
          end;
     
          // On vérifie si RAW.TEXT (le code-source) contient l'expression "utf-8".
          // Ici nous utilisons POS mais nous pouvions utiliser ANSICONTAINSSTR.
          if Pos('utf-8', Raw.Text) <> 0 then
            Resultat := 1 // La réponse est oui !
          else
            Resultat := 0; // La réponse est non !
     
          // On libère les composants utilisés via FREE ou FREEANDNIL.
          Raw.Free;
          HTTP.Free;
     
          // On synchronise la réponse avec la procédure FINISH,
          // qui pourra intéragir alors avec l'interface.
          Synchronize(Finish);
        end;
      end;
     
      // Le thread est terminé donc on retire (décrémente) "-1" à la StringList.
      // Pour rappel, THREADS est un Integer.
      Dec(Threads);
     
      // Plus de threads dans la liste, on en déduit que l'opération est terminée !
      if Threads <= 0 then
        ShowMessage('Traitement complet terminé !');
    end;
     
    // Nous modifions la ligne de l'URL en cours lorsque l'opératon commence.
    procedure TDemoThread.Initialize;
    begin
      // Intéraction avec l'interface possible,
      // car cette procédure est appelée via SYNCHRONIZE.
      FormMain.ListBox.Items.Strings[LigneActive] := URL + ' - En cours...';
    end;
     
    // L'opération est terminée, place à l'affectation des résultats.
    procedure TDemoThread.Finish;
    begin
      case Resultat of
        1: // Résultat positif, donc l'URL contient l'expression !
          begin
            // Intéraction avec l'interface car SYNCHRONIZE :)
            FormMain.ListBox.Items.Strings[LigneActive] :=
              URL + ' - Contient l''expression "utf-8"';
          end;
        0: // Résultat négatif, donc l'URL ne contient pas l'expression !
          begin
            // Intéraction avec l'interface car SYNCHRONIZE :)
            FormMain.ListBox.Items.Strings[LigneActive] :=
              URL + ' - Ne contient pas l''expression "utf-8"';
          end;
      end;
    end;
     
    { ============================================================================ }
     
    procedure TFormMain.ButtonStartClick(Sender: TObject);
    var
      i: Integer;
    begin
      // On vérifie que le ListBox contient bien des éléments,
      // sinon ça risque de ne pas fonctionner...
      // Bien entendu, cette vérification pourrait être plus poussée.
      if FormMain.ListBox.Items.Count > 0 then
      begin
        // Nous passons WORK à TRUE afin d'indiquer au programme
        // que l'opération est lancée !
        Work := True;
     
        // Si le nombre de threads souhaités est supérieur au nombre d'URLs
        // à traiter, alors on baisse le nombre de threads automatiquement.
        if SpinEditThreads.Value > ListBox.Items.Count then
          SpinEditThreads.Value := ListBox.Items.Count;
     
        // Afin de ne pas utiliser le ListBox (donc l'interface),
        // nous utiliserons une StringList
        SL.Assign(ListBox.Items);
     
        // LIGNE (Integer) sera la position actuelle dans la StringList (SL).
        // Nous devons l'initialiser à "-1" car le début du thread
        // va l'incrémenter de "+1" (INC) ; LIGNE se doit donc de partir de 0.
        Ligne := -1;
     
        // Nous indiquons le nombre de threads choisi par l'utilisateur.
        Threads := SpinEditThreads.Value;
     
        // Voici enfin la création de chaque thread !
        // Un SPINEDIT est utilisé afin de définir le nombre de threads maximum.
        for i := 1 to SpinEditThreads.Value do
          TDemoThread.Create(False);
      end
      else
        // ListBox vide, donc on engueule l'utilisateur, c'est normal :D
        ShowMessage('Je te laisse deviner l''erreur...');
    end;
     
    procedure TFormMain.ButtonStopClick(Sender: TObject);
    begin
      // Si "WORK=TRUE" on en déduit que l'opération est déjà en cours...
      if Work then
      begin
        // Sinon, on passe WORK à FALSE afin qu'auncun nouveau thread ne soit créé.
        Work := False;
     
        // Puis un message indiquant à l'utilisateur que l'opération a été stoppée.
        ShowMessage('Stoppé ! Attendons la fin des derniers threads actifs...');
      end
      else
        // ...donc voici un beau message pour en informer l'utilisateur.
        // Il va de soit qu'il est plus élégant de désactiver les controls
        // inutiles lorsque l'opération est en cours.
        // Mais faisons très simple ici :)
        ShowMessage('Rien à stopper, l''opération n''a pas commencée !');
    end;
     
    procedure TFormMain.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
      // On libère la StringList avant de fermer.
      SL.Free;
     
      // On libère la CriticalSection avant de fermer.
      CS.Free;
    end;
     
    procedure TFormMain.FormCreate(Sender: TObject);
    begin
      // On crée la StringList qui servira à stocker de manière virtuelle
      // le contenu du ListBox.
      SL := TStringList.Create;
     
      // On crée la CriticalSection qui servira à indiquer l'action
      // qui devra être réalisée par les threads un par un,
      // et non simultanément (pour éviter les conflits).
      CS := TCriticalSection.Create;
    end;
     
    end.
    Bonne soirée

    Beny
    Fichiers attachés Fichiers attachés

  15. #35
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 445
    Points
    28 445
    Par défaut
    juste une petite remarque, tu utilises un section critique pour accéder à la liste, c'est une solution, mais juste derrière tu "Synchronize" un appel avec le Thread principal...il serait plus simple de se servir de cet appel pour récupérer l'URL

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    procedure TDemoThread.Initialize;
    begin
      if LigneActive < FormMain.ListBix.Items.Count then
      begin
        URL := FormMain.ListBox.Items.Strings[LigneActive];
        FormMain.ListBox.Items.Strings[LigneActive] := URL + ' - En cours...';
        Inc(LigneActive);
      end else
        URL = ''; // rien à traiter
    end;
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 698
    Points : 13 137
    Points
    13 137
    Par défaut
    • Il manque la destruction des threads.
    • Dec(Threads) devrait également être protégé.
    • Application.ProcessMessages à éviter (VCL). De plus inutile puisque le thread principal n'est pas bloqué.
    • Le bloc try..except devrait conditionner la suite du code. Pourquoi continuer le traitement en cas d'erreur ?
    • Je verrais plus Resultat comme un booléen. (à moins qu'il y ait une gestion de numéro d'erreur)
    • Ne pas oublier les méthodes anonymes. Synchronize(Initialize) pourrait être remplacé par:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    synchronize(procedure
                begin
                  FormMain.ListBox.Items.Strings[LigneActive] := URL + ' - En cours...';
                end);

  17. #37
    Membre régulier
    Homme Profil pro
    Inscrit en
    Août 2006
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Août 2006
    Messages : 108
    Points : 82
    Points
    82
    Par défaut
    Citation Envoyé par Paul TOTH Voir le message
    juste une petite remarque, tu utilises un section critique pour accéder à la liste, c'est une solution, mais juste derrière tu "Synchronize" un appel avec le Thread principal...il serait plus simple de se servir de cet appel pour récupérer l'URL
    Bien vu, merci

    Bêtement, je n'avais pas pensé sur le coup que le Synchronize permettait d'éviter les conflits, tout autant que la CriticalSection dans ce cas précis.

    J'ai mis à jour cela (voir code plus bas).

    Citation Envoyé par Andnotor Voir le message
    • Il manque la destruction des threads.
    • Dec(Threads) devrait également être protégé.
    • Application.ProcessMessages à éviter (VCL). De plus inutile puisque le thread principal n'est pas bloqué.
    • Le bloc try..except devrait conditionner la suite du code. Pourquoi continuer le traitement en cas d'erreur ?
    • Je verrais plus Resultat comme un booléen. (à moins qu'il y ait une gestion de numéro d'erreur)
    • Ne pas oublier les méthodes anonymes. Synchronize(Initialize) pourrait être remplacé par:
    Merci pour ces remarques
    Je pense avoir tout corriger ; je détail :

    Pour la destruction des threads, j'ai ajouté FreeOnTerminate := True; dans le "constructor" (Create) de mon thread.
    Cela suffit-il ?

    Pour protéger Dec(Threads); je l'ai placé dans une CriticalSection.
    Aurais-je pu utiliser un Synchronize (méthode classique ou anonyme) ?

    Pour le Application.ProcessMessages;, c'était un réflexe, je n'ai pas pu m'en empêcher

    Pour conditionner la suite du code, j'ai déclaré une variable interne au thread PeutContinuer: Boolean; que j'initialise à "True" ; puis, en cas d'erreurs du GET, "PeutContinuer" passe à "False".
    Pour continuer la procédure, j'utilise la condition suivante : if PeutContinuer and (Length(Raw.Text) > 0) then ... else Resultat := 0;.

    Effectivement "Resultat" pourrait être en boolean.

    Pour les méthodes anonymes, personnellement je ne trouve pas ça très jolie visuellement... :s
    Y à-t-il des avantages à utiliser des méthodes anonymes plutôt qu'une synchronisation classique ?

    Merci en tout cas pour vos conseils

    Voici mon code avec les corrections :
    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
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    unit Main;
     
    interface
     
    uses
      // Pour synchroniser les threads, vous aurrez besoin de "System.SyncObjs".
      // Pour utiliser Indy (GET), vous aurez besoin de "IdHTTP".
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
      System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
      Vcl.StdCtrls, Vcl.Samples.Spin, System.SyncObjs, IdHTTP;
     
    type
      TFormMain = class(TForm)
        ListBox: TListBox;
        LabelThreads: TLabel;
        SpinEditThreads: TSpinEdit;
        ButtonStart: TButton;
        ButtonStop: TButton;
        LabelTitre: TLabel;
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
        procedure FormCreate(Sender: TObject);
        procedure ButtonStartClick(Sender: TObject);
        procedure ButtonStopClick(Sender: TObject);
      private
      public
      end;
     
      // La CLASS de notre thread.
      TDemoThread = class(TThread)
        // Dans PRIVATE nous plaçons les variables qui seront modifiées
        // par les différents threads simultanément, et qui pourront communiquer
        // entre le thread et les synchronisations sans interférences.
      private
        URL: String;
        LigneActive, Resultat: Integer;
      protected
        // La procédure principal.
        procedure Execute; override;
      public
        // Pour la synchronisation de fin de procédure.
        procedure Finish;
        // Pour la synchronisation de début de procédure.
        procedure Initialize;
        // Ce qui lancera chaque thread.
        constructor Create(CreateSuspended: Boolean);
      end;
     
    var
      FormMain: TFormMain;
      CS: TCriticalSection; // La CriticalSection (voir FormCreate plus bas).
      SL: TStringList; // La StringList (voir FormCreate plus bas).
      Threads, Ligne: Integer; // Nous y reviendrons plus tard...
      Work: Boolean; // Quand l'opération commence, WORK passe à TRUE.
     
    implementation
     
    {$R *.dfm}
     
    // Le thread est crée ici.
    constructor TDemoThread.Create(CreateSuspended: Boolean);
    begin
      // Le thread se libère tout seul quand il termine.
      FreeOnTerminate := True;
     
      // Le thread est crée puis lancé directement si CREATESUSPENDED est à FALSE.
      // Sinon il faudra utiliser START ou RESUME.
      inherited Create(CreateSuspended);
    end;
     
    // Voici le code principal du thread.
    // Vous verrez qu'il n'interagit jamais avec l'interface, 
    // cette étape sera gérée par les synchronisations que nous verrons plus bas.
    procedure TDemoThread.Execute;
    var
      Raw: TStringList; // StringList temporaire pour stocker le code-source.
      HTTP: TIdHTTP; // On déclare ici le composant HTTP de Indy.
      PeutContinuer: Boolean;
    begin
      // Si "WORK=TRUE" l'opération continue normalement...
      while Work do
      begin
        // On intéragit avec l'interface afin que l'utilisateur sache
        // ce qu'il se passe et où nous en sommes.
        // (Rendez-vous dans la procédure INITIALIZE pour plus d'infos.)
        Synchronize(Initialize);
     
        // Si la vérification effectuée ci-dessus donne un résultat positif
        // alors nous pouvons procéder à l'opération.
        if Work then
        begin
          // On crée la StringList temporaire.
          Raw := TStringList.Create;
     
          // On crée le composant HTTP et on le paramètre vite-fait, bien-fait.
          HTTP := TIdHTTP.Create;
          HTTP.HandleRedirects := True;
          HTTP.ReadTimeout := 15000;
          HTTP.ConnectTimeout := 15000;
     
          // On initialise la boolean PEUTCONTINUER à TRUE.
          PeutContinuer := True;
     
          // Dans un TRY/EXCEPT on fait un GET pour récupérer le code source
          // de l'URL, que l'on va affecter à la StringList créée précédemment.
          try
            Raw.Text := HTTP.Get(URL);
          except
            // En cas d'erreurs, PEUTCONTINUER tourne à FALSE afin
            // de conditionner le reste de l'opération.
            PeutContinuer := False;
          end;
     
          // Si aucune erreurs pendant le GET et que le code-source récupéré
          // n'est pas vide, alors on peut continuer.
          if PeutContinuer and (Length(Raw.Text) > 0) then
          begin
            // On vérifie si RAW.TEXT (le code-source) contient l'expression "utf-8".
            // Ici nous utilisons POS mais nous pouvions utiliser ANSICONTAINSSTR.
            if Pos('utf-8', Raw.Text) <> 0 then
              Resultat := 1 // La réponse est oui !
            else
              Resultat := 0; // La réponse est non !
          end
          else
            Resultat := 0;
     
          // On libère les composants utilisés via FREE ou FREEANDNIL.
          Raw.Free;
          HTTP.Free;
     
          // On synchronise la réponse avec la procédure FINISH,
          // qui pourra intéragir alors avec l'interface.
          Synchronize(Finish);
        end;
      end;
     
      // Nous entrons en section critique...
      CS.Enter;
     
      // Le thread est terminé donc on retire (décrémente) "-1" à la StringList.
      // Pour rappel, THREADS est un Integer.
      Dec(Threads);
     
      // Nous quittons la section critique.
      CS.Leave;
     
      // Plus de threads dans la liste, on en déduit que l'opération est terminée !
      if Threads <= 0 then
        ShowMessage('Traitement complet terminé !');
    end;
     
    // Nous modifions la ligne de l'URL en cours lorsque l'opératon commence.
    procedure TDemoThread.Initialize;
    begin
      // Ici nous allons vérifier s'il reste des URLs à traiter.
      // Nous allons utiliser ici la CriticalSection afin que cette opération
      // ne soit pas effectuée simultanément par plusieurs threads ;
      // ce qui fausserait le résultat.
     
      // Nous incrémentons de "+1" la position actuelle dans la StringList
      // contenant les URLs à traiter.
      // Pour rappel, LIGNE est un Integer.
      Inc(Ligne);
     
      // Si la position actuelle est inférieur à la dernière ligne
      // de la StringList, alors nous allons pouvoir traiter cette URL.
      if Ligne < SL.Count then
      begin
        // Nous utilisons une seconde variable Integer pour indiquer
        // la position actuelle dans la list (optionnel, je pense).
        LigneActive := Ligne;
     
        // On récupère l'URL en cours.
        URL := SL[LigneActive];
     
        // Intéraction avec l'interface possible,
        // car cette procédure est appelée via SYNCHRONIZE.
        FormMain.ListBox.Items.Strings[LigneActive] := URL + ' - En cours...';
      end
      else
        // Sinon, on en déduit qu'il n'y a plus d'URLs à traiter.
        Work := False;
    end;
     
    // L'opération est terminée, place à l'affectation des résultats.
    procedure TDemoThread.Finish;
    begin
      case Resultat of
        1: // Résultat positif, donc l'URL contient l'expression !
          begin
            // Intéraction avec l'interface car SYNCHRONIZE :)
            FormMain.ListBox.Items.Strings[LigneActive] :=
              URL + ' - Contient l''expression "utf-8"';
          end;
        0: // Résultat négatif, donc l'URL ne contient pas l'expression !
          begin
            // Intéraction avec l'interface car SYNCHRONIZE :)
            FormMain.ListBox.Items.Strings[LigneActive] :=
              URL + ' - Ne contient pas l''expression "utf-8"';
          end;
      end;
    end;
     
    { ============================================================================ }
     
    procedure TFormMain.ButtonStartClick(Sender: TObject);
    var
      i: Integer;
    begin
      // On vérifie que le ListBox contient bien des éléments,
      // sinon ça risque de ne pas fonctionner...
      // Bien entendu, cette vérification pourrait être plus poussée.
      if FormMain.ListBox.Items.Count > 0 then
      begin
        // Nous passons WORK à TRUE afin d'indiquer au programme
        // que l'opération est lancée !
        Work := True;
     
        // Si le nombre de threads souhaités est supérieur au nombre d'URLs
        // à traiter, alors on baisse le nombre de threads automatiquement.
        if SpinEditThreads.Value > ListBox.Items.Count then
          SpinEditThreads.Value := ListBox.Items.Count;
     
        // Afin de ne pas utiliser le ListBox (donc l'interface),
        // nous utiliserons une StringList
        SL.Assign(ListBox.Items);
     
        // LIGNE (Integer) sera la position actuelle dans la StringList (SL).
        // Nous devons l'initialiser à "-1" car le début du thread
        // va l'incrémenter de "+1" (INC) ; LIGNE se doit donc de partir de 0.
        Ligne := -1;
     
        // Nous indiquons le nombre de threads choisi par l'utilisateur.
        Threads := SpinEditThreads.Value;
     
        // Voici enfin la création de chaque thread !
        // Un SPINEDIT est utilisé afin de définir le nombre de threads maximum.
        for i := 1 to SpinEditThreads.Value do
          TDemoThread.Create(False);
      end
      else
        // ListBox vide, donc on engueule l'utilisateur, c'est normal :D
        ShowMessage('Je te laisse deviner l''erreur...');
    end;
     
    procedure TFormMain.ButtonStopClick(Sender: TObject);
    begin
      // Si "WORK=TRUE" on en déduit que l'opération est déjà en cours...
      if Work then
      begin
        // Sinon, on passe WORK à FALSE afin qu'auncun nouveau thread ne soit créé.
        Work := False;
     
        // Puis un message indiquant à l'utilisateur que l'opération a été stoppée.
        ShowMessage('Stoppé ! Attendons la fin des derniers threads actifs...');
      end
      else
        // ...donc voici un beau message pour en informer l'utilisateur.
        // Il va de soit qu'il est plus élégant de désactiver les controls
        // inutiles lorsque l'opération est en cours.
        // Mais faisons très simple ici :)
        ShowMessage('Rien à stopper, l''opération n''a pas commencée !');
    end;
     
    procedure TFormMain.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
      // On libère la StringList avant de fermer.
      SL.Free;
     
      // On libère la CriticalSection avant de fermer.
      CS.Free;
    end;
     
    procedure TFormMain.FormCreate(Sender: TObject);
    begin
      // On crée la StringList qui servira à stocker de manière virtuelle
      // le contenu du ListBox.
      SL := TStringList.Create;
     
      // On crée la CriticalSection qui servira à indiquer l'action
      // qui devra être réalisée par les threads un par un,
      // et non simultanément (pour éviter les conflits).
      CS := TCriticalSection.Create;
    end;
     
    end.
    Beny

  18. #38
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 445
    Points
    28 445
    Par défaut
    voir aussi les fonctions Windows InterlockedIncrement et InterlockedDecrement
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  19. #39
    Membre régulier
    Homme Profil pro
    Inscrit en
    Août 2006
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Août 2006
    Messages : 108
    Points : 82
    Points
    82
    Par défaut
    Citation Envoyé par Paul TOTH Voir le message
    voir aussi les fonctions Windows InterlockedIncrement et InterlockedDecrement
    Merci pour l'idée, je ne connaissais pas.

    Apparemment cette fonction permet d'incrémenter (ou de décrémenter) de manière "sécurisée" (sans passer par une section critique), si j'ai bien compris.

    Un article intéressant : http://blog.synopse.info/post/2011/0...i-applications

    Don't abuse on critical sections, let them be as small as possible, but rely on some atomic modifiers if you need some concurrent access - see e.g. InterlockedIncrement / InterlockedExchangeAdd;
    Beny

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 2 PremièrePremière 12

Discussions similaires

  1. Réponses: 2
    Dernier message: 14/04/2009, 15h17
  2. Jasper : première tentative
    Par Peanut dans le forum Jasper
    Réponses: 8
    Dernier message: 13/02/2009, 10h02
  3. [AJAX] [DWR] Première tentative avec Ajax
    Par bzoler dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 27/03/2008, 17h12
  4. [javamail]première tentative échouée
    Par jijaLaClasse dans le forum API standards et tierces
    Réponses: 5
    Dernier message: 22/11/2007, 20h12

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