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

Langage Delphi Discussion :

Attendre Fin Threads


Sujet :

Langage Delphi

  1. #1
    Membre à l'essai
    Inscrit en
    Octobre 2006
    Messages
    22
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 22
    Points : 12
    Points
    12
    Par défaut Attendre Fin Threads
    Bonjour a tous,

    J'aimerais attendre la fin de plusieurs threads, voici la méthode que j'utilise:

    code exécutant les threads :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    var
      loop: Integer;
      nbThreadFini: Byte;
    begin
      for loop:= 0 to FPlateaux.Count - 1 do
      begin
        with FPlateaux do
          TThreadPlateau.Create(Items[loop], NumPoint, nbThreadFini);
      end;
     
      repeat
        Application.ProcessMessages;
      until nbThreadFini = FPlateaux.Count;
    Pour expliquer rapidement:
    FPlateaux est une liste de plateau. Donc je crée un thread en lui passant le plateau (items[loop]), une variable NumPoint pour le traitement interne et une variable nbThreadFini pour déterminé le nombre de thread fini.

    Voici le code du thread :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    TThreadPlateau=class(TThreadCustom)
      private
        FPlateau: TPlateau;
        FNumeroPoint: Integer;
        PThreadFini: PByte;
        procedure eventTerminate(Sender: TObject); override;
      protected
        procedure Execute; override;
      public
        constructor Create(Valeur: TPlateau; NumPoint: Integer; threadFini: Integer); reintroduce;
      end;
    L'évènement EventTerminate est appelé quand le thread se termine et voici l'implémentation de ma classe :

    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
     
    constructor TThreadPlateau.Create(Valeur: TPlateau; numPoint: Integer; threadFini: Integer);
    begin
      inherited Create;
      FNumeroPoint:= NumPoint;
      FPlateau:= Valeur;
      PThreadFini:= @threadFini;
      resume;
    end;
     
    procedure TThreadPlateau.Execute;
    begin
      FPlateau.DemarrageActions(FNumeroPoint);
    end;
     
    procedure TThreadPlateau.eventTerminate(Sender: TObject);
    var
      SectionCritique: TCriticalSection;
    begin
      SectionCritique:= TCriticalSection.Create;
      SectionCritique.Enter;
      Inc(PThreadFini^);
      SectionCritique.Leave;
      SectionCritique.Free;
    end;
    Comme vous remarquez j'utilise un pointeur de la variable nbThreadFini que j'incrémente a la fin du thread dans une section critique.

    Donc pour savoir si tous mes threads sont terminé je regarde que j'ai autant de threads finis que crées.

    J'aurais voulu savoir si cette méthode est bonne et si il n'éxitait pas une meilleur méthode pour attendre la fin de tous mes threads ?

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    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 459
    Points : 24 873
    Points
    24 873
    Par défaut
    On se demande à quoi ça sert d'avoir des Threads si c'est pour les attendre avec une boucle sur Application.ProcessMessages qui sollicite au maximum le processeur !

    utilise OnTerminate, ou le surcharge le destructeur (et active FreeOnTerminate)
    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
    Expert éminent sénior

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Points : 10 154
    Points
    10 154
    Par défaut
    Oh si ! Il existe beaucoup mieux ! La méthode WaitFor de TThread.
    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
    var
      loop: Integer;
      Threads: array of TThread;
    begin
      SetLength(Threads, FPlateaux.Count);
     
      for loop:= 0 to FPlateaux.Count - 1 do
      begin
        with FPlateaux do
          Threads[loop] := TThreadPlateau.Create(Items[loop], NumPoint);
      end;
     
      for loop := 0 to FPlateaux.Count - 1 do
        Threads[loop].WaitFor;
    end;
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  4. #4
    Membre à l'essai
    Inscrit en
    Octobre 2006
    Messages
    22
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 22
    Points : 12
    Points
    12
    Par défaut
    ShaiLeTroll : Les threads sont là car l'éxécution des Plateaux est très longues et qu'on gagnerait du temps a les faire exécuter en parralèle (pour information le traitement d'un plateau peut prendre jusqu'a une heure).

    Après j'utilise un application.processMessage pour ne pas avoir une application figé pendant le traitement. Est-ce que sa serait mieux de faire un application.HandleMessage ?

    C'est pourquoi je pose la question sur le forum, voir si il n'y a pas de solution plus avantageuse...

    sjrd : Est ce que le WaitFor n'est pas bloquant pour mon application ?

  5. #5
    Expert éminent sénior

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Points : 10 154
    Points
    10 154
    Par défaut
    Citation Envoyé par Drikcé Voir le message
    sjrd : Est ce que le WaitFor n'est pas bloquant pour mon application ?
    Si bien entendu. Si ça te pose un problème, la solution est de mettre tout le traitement dans un thread (qui lance les autres puis les attend).
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  6. #6
    Membre à l'essai
    Inscrit en
    Octobre 2006
    Messages
    22
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 22
    Points : 12
    Points
    12
    Par défaut
    Je comprend sjrd, mais si je met le traitment dans un nouveau Thread qu'on va appeler threadTraitement, c'est que je vais devoir toujours attendre la fin de mon nouveau ThreadTraitement....

    Il n'existe pas un solution propre permettant d'attendre la fin de plusieurs threads sans que cela bloque l'application ou sans utiliser le processeur a fond ?

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 693
    Points : 13 128
    Points
    13 128
    Par défaut
    Pour ne pas utiliser le processeur "à fond", il suffit de mettre un Sleep(10) dans ta boucle.

    La meilleure façon (à mon avis) d'attendre la fin des threads est d'utiliser WaitForMultipleObjects sur un tableau de ThreadID. Soit depuis un thread de contrôle comme proposé par sjrd, soit en gérant WAIT_TIMEOUT dans une boucle.

  8. #8
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    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 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Il faut programmer de façon évenementielle !
    OnTerminate est là pour cela ! (même si bcp sur le forum ont eu des problèmes avec, ce qui n'a jamais été mon cas)
    Tu peux mettre tes propres event durant le Execute (progression et fin du execute)
    Sur le forum, tu as bcp de sujet qui traite sur l'attente d'un Thread

    Il te faut gérer biensur un système de lock pour éviter que l'on puisse lancer d'autres taches avant que le calcul des plateaux soit fini depuis la fenêtre de l'application !

    Ta section SectionCritique ne sert à rien du tout !
    L'objet doit être partagé pour que cela fasse quelques choses d'intéressant !

    Sinon, la solution simple pas très élégant, c'est d'avoir un Timer qui une fois tout les threads terminés lance l'action suivante ...

    sinon, le sleep comme cité est une solution pour attendre !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
      repeat
        Application.ProcessMessages;
        Sleep(0); // Juste ce qu'il faut pour soulager le proc, a peu près 0.002 ms
      until nbThreadFini = FPlateaux.Count;
    tu peux passer à sleep(1), mais faut savoir que cela passe à 1.950 ms, le temps du sleep(0) peut légèrement augmenter si tu as d'autres threads qui calculent bcp par contre le proc est quasiment au minimum d'utilisation pour ton thread d'attente
    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

  9. #9
    Membre à l'essai
    Inscrit en
    Octobre 2006
    Messages
    22
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 22
    Points : 12
    Points
    12
    Par défaut
    Mon eventTerminate est relié a l'évènement onTerminate. Si tu veux j'ai mis une variable en partage (pointeurs) a tous mes threads pour savoir quand tous mes threads étaient terminé. C'est pour évitez de faire des repeat imbriqué du style :

    repeat
    repeat

    until thread2.terminated;
    until thread1.Terminated;

    Sachant que le nombre de threads peut varier dynamiquement de 1 a 3....

    La section critique était la pour éviter que deux threads écrivent en même temps dans la variable partagée. Mais tu as surement raison c'est inutile...

    Sinon j'ai trouver une autre solution sans passé par la variable commune a tous les threads pour tester la fin du thread :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    repeat
        retour:= WaitForMultipleObjects(3, @tableauHandle, True, 10);
        Application.ProcessMessages;
    until retour = WAIT_OBJECT_0;
    Je sais si c'est mieux que la boucle que tu viens de me présenté ? Elle a l'avantage de ne pas faire de traitement sur une variable commune a tous les threads.

    Sinon je tiens a vous remercier pour toutes les réponses que vous m'avez donné jusqu'à présent en espérant trouver la solution

  10. #10
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

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

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 170
    Points
    4 170
    Par défaut
    Citation Envoyé par Drikcé Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    repeat
        retour:= WaitForMultipleObjects(3, @tableauHandle, True, 10);
        Application.ProcessMessages;
    until retour = WAIT_OBJECT_0;
    Je sais si c'est mieux que la boucle que tu viens de me présenté ?
    En fait, c'est la méthode que te suggérait Andnotor. Tu utilises WaitForMultipleObjects pour attendre la fin des threads, avec un TimeOut (10ms pour ensuite traiter des messages, c'est franchement court, tu peux certainement monter à 100...). Durant ce temps, le thread est bloqué et n'utilise pas inutilement le CPU , qui est alors pleinement utilisable par les autres threads.
    A l'issu du timeout tu traites les messages windows et tu te remet en attente.

    La section critique était la pour éviter que deux threads écrivent en même temps dans la variable partagée. Mais tu as surement raison c'est inutile...
    Tu n'as pas compris. Les sections critiques ça ne fonctionne pas comme ça !
    C'est un sémaphore optimisé en utilisant un spinlock avant de se mettre en attente sur le sémaphore. Une section critique n'arrête pas l'exécution des autres threads, elle ne te garantis pas qu'un autre thread n'ira pas modifier tes données en même temps.
    Tout ce qu'elle garanti, c'est que deux thread différents fassent le Enter sur la même section critique (la même instance de l'objet) en même temps.
    Si chaque thread crée sa propre instance au lieu d'accéder à la même section, ils pouront tous obtenir l'accès à leur section en même temps. Ta section ne protège donc rien du tout...
    De plus pour incrémenter une variable de façon threadsafe, il existe InterlockedIncrement.

  11. #11
    Membre à l'essai
    Inscrit en
    Octobre 2006
    Messages
    22
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 22
    Points : 12
    Points
    12
    Par défaut
    Merci pour ses explications Frank .

    Donc cette méthode d'attente des threads est valable en sachant que je n'utilise pas cette boucle d'attente dans un thread ?

    En ce qui concerne les sections critiques :

    Les sections critiques ne sont pas à proprement parler des objets de synchronisation. C’est une sorte de signal qui bloque
    tous les threads rattachés à un même processus
    . Mais si d’autres threads dépendants d’autres processus veulent accéder à
    la ressource, alors il y a risque de violation. Le principe de fonctionnement est des plus simples. Lors de son execution,
    le thread annonce aux autres threads du processsus qu’il entre dans une section critique. Automatiquement, l’exécution
    des autres threads rattachés au processus sont bloqués. Ils seront libérés lorsque le thread annoncera qu’il est sorti de la
    section critique.
    Delphi propose un objet TCriticalSection pour simplifier l’usage des sections critiques.
    Non je ne comprends plus l'intérêt des sections critiques dans ton explication Frank. Si je doit l'utiliser comme un sémaphore, je laisse tomber la section critique et j'utilise des mutexs. Enfin je vais plutôt jeter un coup d'œil sur InterlockedIncrement qui a l'air plus intéressant dans mon cas.

    J'aurais une dernière question toujours sur les threads, vu que j'ai un responsable assez pointilleux :

    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
    TThreadPlateau=class(TThreadCustom)
      private
        PThreadFini: PByte;
        FFinThread: Boolean;
        procedure eventTerminate(Sender: TObject); override;
      protected
        procedure Execute; override;
      public
        constructor Create(threadFini: PByte); reintroduce;
        property FinThread: Boolean read FFinThread write FFinThread;
      end;
     
     
    constructor TThreadPlateau.Create(threadFini: PByte);
    begin
      inherited Create;
      PThreadFini:= threadFini;
     
      FFinThread:= False;
      resume;
    end;
     
    procedure TThreadPlateau.Execute;
    begin
      repeat
        Sleep(100);
      until FFinThread;
    end;
    C'est un thread de test en fait pour tester le PC et les timers en parrallèle. Donc pour terminer mon thread je passe ma variable FinThread a Vrai.
    J'ai tester et sa fonctionne mais on me dis que cette façon de faire est dangereuse et qu'il vaut mieux passer par des évènements pour stopper le thread ?

  12. #12
    Expert éminent sénior

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Points : 10 154
    Points
    10 154
    Par défaut
    Citation Envoyé par Drikcé Voir le message
    En ce qui concerne les sections critiques :
    D'où sors-tu ça ? Cette source est complètement fausse.
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  13. #13
    Membre à l'essai
    Inscrit en
    Octobre 2006
    Messages
    22
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 22
    Points : 12
    Points
    12
    Par défaut
    En fait je l'ai trouvé sur le tutoriel a cette adresse :

    http://lberne.developpez.com/delphi/Proc-Thread/

    Après je pense qu'une section critique permet d'empêcher d'autre thread d'accéder a la même partie du code tant que celle ci n'a pas été libéré... Il faudrait pousser la question... Sinon on utiliserait des synchronisations qui obligerait de les partager a tous les threads. Si la définition est fausse, qu'elle est l'intérêt des sections critiques ?

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 693
    Points : 13 128
    Points
    13 128
    Par défaut
    Utiliser une section critique n'est pas faux, c'est ton implémentation qui l'est

    Il n'y a pas qu'une section critique par processus, mais autant que tu en crées. Dans ton implémentation, chaque thread crée la sienne alors qu'ils devraient en fait accéder à une seule section critique globale. (Le thread principale y compris)

  15. #15
    Membre à l'essai
    Inscrit en
    Octobre 2006
    Messages
    22
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 22
    Points : 12
    Points
    12
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    Utiliser une section critique n'est pas faux, c'est ton implémentation qui l'est

    Il n'y a pas qu'une section critique par processus, mais autant que tu en crées. Dans ton implémentation, chaque thread crée la sienne alors qu'ils devraient en fait accéder à une seule section critique globale. (Le thread principale y compris)
    D'accord je comprends mais tous mes threads appartiennent a un seul et même processus de l'application.... Je comprends ce que tu veux dire: chaque thread est un processus mais il sont tous rattaché a mon processus principal. C'est la ou il y a ambiguité...

    Car si je dois faire passer la classe TCriticalSection a tous mes threads pour exécuter la section critique, je préfère faire passer un mutex ou un sémaphore cela sera moins contraignant. C'est la ou je comprend pas l'intérêt de la section critique dans son implémentation.

    Et d'apres la définition:
    Le principe de fonctionnement est des plus simples. Lors de son execution,
    le thread annonce aux autres threads du processsus qu’il entre dans une section critique.
    De plus:

    Automatiquement, l’exécution
    des autres threads rattachés au processus sont bloqués. Ils seront libérés lorsque le thread annoncera qu’il est sorti de la
    section critique
    Si on part du principe qu'un thread est un processus (ce qui est en quelque sorte vrai) je ne vois pas comment crée plusieurs threads qui pourrait appartenir au même processus sauf au processus principal....

    Enfin il faudrait vraiment tester ces sections critiques. Pour ma part j'ai laissé tomber xD

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 693
    Points : 13 128
    Points
    13 128
    Par défaut
    Les threads ne sont pas des processus
    Un processus égal une application.

    Comme dit par sjrd, cette définition est fausse. Il n'y a aucune notification d'aucune sorte et pas de blocage automatique. (encore heureux !)

    Un 1er thread verrouille l'accès par Acquire. Les autres threads tournent toujours.
    Un 2ème thread veut accéder au même code. Il appelle aussi Acquire et se retrouve suspendu jusqu'à ce que le 1er thread déverrouille l'accès (Release).
    Et ainsi de suite...

    Il n'y a pas besoin de passer l'objet section critique à chaque thread. Il suffit de déclarer la variable en global pour qu'ils y aient tous accès.

  17. #17
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

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

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 170
    Points
    4 170
    Par défaut
    Citation Envoyé par Drikcé Voir le message
    Car si je dois faire passer la classe TCriticalSection a tous mes threads pour exécuter la section critique, je préfère faire passer un mutex ou un sémaphore cela sera moins contraignant. C'est la ou je comprend pas l'intérêt de la section critique dans son implémentation.
    Comme ça a été déjà dit, la définition que tu as cité est fausse. C'est une confusion que beaucoup de gens font, à mon avis pour deux raisons :
    - Dans la théorie de la programmation parallèle, une section critique est un bloc de code (qui s'exécute pour un traitement dit "critique" (au sens time critical)) qui doit s'exécuter du début à la fin sans être interrompu. Autrement dit, sous Windows, ça veux dire masquer les interruptions. La section critique n'a aucun sens dans une application utilisateur.
    - Sans doute à cause du premier point, l'aide en ligne de Delphi dit la chose suivante :
    TCriticalSection permet à un seul thread d'une application multithread de bloquer temporairement l'accès à un bloc de code aux autres threads.
    D'une certaine manière, ce n'est pas totalement faux, mais on comprend que les autres threads s'arrêtent, ce qui n'est pas le cas. Ils seront seulement bloqués s'ils essaient d'accéder à la section critique.

    Maintenant quel est l'intérêt d'une section critique plutôt qu'un sémaphore ou un mutex ?
    C'est très simple : La section critique est un mutex plus performant dans le cas d'une machine multi CPU (pour un mono-CPU, c'est strictement la même chose).

    La plupart du temps, le mutex utilisé pour protéger l'accès à une variable restera bloqué pendant un laps de temps très très court. A peines quelques microsecondes.
    Si tu utilises un mutex pour faire la synchronisation et qu'au moment d'obtenir le mutex il est déjà en cours d'utilisation, Windows va bloquer ton thread et le mettre en sommeil jusqu'à ce que le mutex se libère.
    Lorsque l'autre thread va libérer le mutex, Windows va marquer le premier thread comme activable, et il faudra attendre une fenêtre CPU disponible avant que le premier thread ne puisse reprendre son exécution. Même si le CPU est libre, endormir et reveiller un thread risque de prendre quelques ms (disons 1 ms pour se fixer un ordre d'idée).

    Donc avec le mutex, le premier thread va se bloquer pendant 1 ms pour accéder à une ressource qui n'est restées verrouillées que quelques microsecondes.

    Le principe d'une section critique, c'est de gérer l'exclusion mutuelle avec une variable globale dans la mémoire du processus avant de faire appel au sémaphore :
    Le premier thread qui verrouille la section va positionner cette variable et le sémaphore (qui est forcément libre puisque la variable l'était).
    Le deuxième thread va tester la variable et se rendre compte que la section est occupée.
    Au lieu de s'endormir, il va se mettre à tester la variable en boucle (donc en gardant le CPU) jusqu'à un nombre maximal d'iterration. Si la section se libère pendant ce temps, il va pouvoir se l'approprier immédiatement, sans avoir eu besoin d'endormir le thread. Cette première attente s'effectuant de façon active, avec une boucle, on parle de "spinlock".
    Si à l'issu du nombre maximal d'itérations, la section n'a toujours pas été libérée, le thread va se mettre en attente du sémaphore et s'endormira pour libérer le CPU.

    Du fait du spinlock dans la mémoire du processus, une section critique ne peut pas être partagée entre deux processus.
    La section criitique ne sert à rien sur une machine monocpu puisque le thread qui a obtenu la section ne risque pas de la libérer s'il n'obtient pas le CPU. Mais Windows gère ça automatiquement en configurant le spinlock des sections critiques à 0 dans le cadre d'une machine mono-cpu.

    Donc en résumé, tu utilises une section critique exactement comme un mutex. Et il vaut mieux s'en servir systématiquement plutôt que de passer par un mutex.

  18. #18
    Membre à l'essai
    Inscrit en
    Octobre 2006
    Messages
    22
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 22
    Points : 12
    Points
    12
    Par défaut
    D'accord, merci beaucoup pour ses explications. C'est plus clair maintenant.

    Juste une dernière question sur les threads et je vous laisse tranquille :

    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
    TThreadPlateau=class(TThreadCustom)
      private
        PThreadFini: PByte;
        FFinThread: Boolean;
        procedure eventTerminate(Sender: TObject); override;
      protected
        procedure Execute; override;
      public
        constructor Create(threadFini: PByte); reintroduce;
        property FinThread: Boolean read FFinThread write FFinThread;
      end;
     
     
    constructor TThreadPlateau.Create(threadFini: PByte);
    begin
      inherited Create;
      PThreadFini:= threadFini;
     
      FFinThread:= False;
      resume;
    end;
     
    procedure TThreadPlateau.Execute;
    begin
      repeat
        // Traitement
      until FFinThread;
    end;
    J'ai crée une propriété finThread pour pouvoir arrêter le thread quand je le souhaite.
    J'ai tester et sa fonctionne mais on me dis que cette façon de faire est dangereuse de passer par une variable "externe" et qu'il vaut mieux passer par des évènements pour stopper le thread (un Tevent serait attendu par mon thread qui serait déclenché par une procédure)?

  19. #19
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

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

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 170
    Points
    4 170
    Par défaut
    Disons surtout que tu as la propriété Terminated qui sert à ça !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    procedure TThreadPlateau.Execute;
    begin
      while not Terminated do
      begin
        // Traitement
      end;
    end;
    En principe dans la boucle tu te mets en attente d'un objet de Synchro qui te signale lorsque le thread a quelque chose à faire.
    Lorsque cet objet est positionné, il se réveille, fait son traitement, et s'il n'a pas été stoppé se remet en attente de l'objet de synchro.

    Lorsque tu veux arrêter le thread, tu appelles sa méthode Terminate. Elle n'a pas d'autre fonction que de positionner Terminated à true pour que le thread se ferme de lui même lors de sa prochaine itération.
    Evidemment, il faut aussi faire quelque chose pour débloquer l'attente sur l'objet de synchro (destruction de l'objet en question, gestion d'un timeout, envoie d'un signal à travers l'objet en question...).

  20. #20
    Membre à l'essai
    Inscrit en
    Octobre 2006
    Messages
    22
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 22
    Points : 12
    Points
    12
    Par défaut
    Merci beaucoup pour toutes ses informations

    Cette discussion a été forte intéressante et instructive.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 8
    Dernier message: 10/10/2011, 13h45
  2. Attendre fin thread
    Par PoZZyX dans le forum Concurrence et multi-thread
    Réponses: 4
    Dernier message: 10/05/2010, 15h58
  3. attendre fin root
    Par cada01a dans le forum Autres Logiciels
    Réponses: 2
    Dernier message: 12/06/2006, 18h29
  4. attendre fin opération
    Par Seb4657 dans le forum Langage
    Réponses: 4
    Dernier message: 05/02/2006, 15h25
  5. [MFC] attendre fin de demarrage d'un processus
    Par pitch21 dans le forum MFC
    Réponses: 16
    Dernier message: 14/10/2004, 09h35

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