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

WinDev Discussion :

Pool de thread, plantent l'appli quand je recharge la fenêtre. Mauvaise terminaison des threads ?


Sujet :

WinDev

  1. #1
    Membre averti Avatar de droliprane
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Mai 2005
    Messages
    710
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Vendée (Pays de la Loire)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : Industrie

    Informations forums :
    Inscription : Mai 2005
    Messages : 710
    Points : 444
    Points
    444
    Par défaut Pool de thread, plantent l'appli quand je recharge la fenêtre. Mauvaise terminaison des threads ?
    Bonjour à toutes et tous,

    dans mon appli de monitoring de bains de galvano, je dois recueillir des infos en provenance d'une quinzaine d'automates.

    Donc dans ma fenêtre de monitoring je lance autant de thread que j'ai d'automates à surveiller :

    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
    PROCEDURE chargerModules()
     
    nomThread est une chaîne
     
    id est un entier
     
    ThreadMode(threadSectionCritique)
     
    POUR TOUT atm 
     
    	id = Val(Droite(atm.atm_ip,3))
    	ZoneRépétéeAjouteLigne(ZR_BOITES,id,"voyant_rouge.png")
     
    	// lance un thread de monitoring par module
    	nomThread="thread_monitoring"+id
    	SI ThreadEtat(nomThread) = threadEnCours ALORS
    		ThreadArrête(nomThread)
    	FIN
    	ThreadExécute(nomThread,threadNormal,"threadMonitoring", id)	
     
    FIN

    La procédure de monitoring se présente comme suit :

    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
    PROCEDURE threadMonitoring(id est un entier)
     
     
    HFiltre(atm,atm_id,hValMin,hValMax,"atm_ip='192.168.0."+id+"'")
    HLitPremier(atm)
    full_ip est une chaîne = atm.atm_ip
    port est un entier = atm.atm_port_tcp
    HDésactiveFiltre(atm)
     
    TANTQUE Vrai
     
    	// MONITORER(id, full_ip, port)
     
    	Multitâche(-100)
     
     
    FIN
    La procédure threadMonitoring exécute la procédure MONITORER (qui va établir la connexion à l'automate, lire les variables et refermer la socket).

    Pour l'instant j'ai commenté la ligne qui lance MONITORER car j'ai déjà un problème de stabilité, on peut même parler de plantage, rien qu'au niveau des threads.

    Je m'explique : il suffit que j'ouvre la fenêtre de monitoring, je la ferme puis je la ré-ouvre et l'appli se fige, "ne répond pas", sablier, "WDTst.exe ne répond pas", et je dois forcer la fermeture.



    Ca plante pareil avec l'exécutable généré.

    Je fais pourtant des threadArrete si threadEnCours à chaque chargement, je ne comprends pas. Et il se passe un temps certain quand je ferme la fenêtre de monitoring pour ouvrir une autre fenêtre qui n'a rien à voir... j'attends 5-10 secondes parfois plus, alors que ça devrait être quasi instantané....

    Quelqu'un peut-il me dire si je m'y prends mal ?

    Merci à vous


    EDIT : je viens de lire ce sujet => http://www.developpez.net/forums/d10...ajoutefichier/ je me demande si je ne suis pas dans une situation semblable
    'Diviser chacune des difficultés en autant de parcelles qu’il se pourrait et qu’il serait requis pour les mieux résoudre', René Descartes

    => Maya GPAO

  2. #2
    Membre averti
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2009
    Messages
    178
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2009
    Messages : 178
    Points : 416
    Points
    416
    Par défaut
    Bonjour,

    L'utilisation de ThreadArrête avant le lancer ne sert à rien où il est placé : bien que lancer en parallèle, le thread est lié à la durée l'élément qui l'a créé. Pas d'application, pas de thread, voir "Durée de vie du thread" dans l'aide de ThreadExécute.

    Concernant votre plantage, il est nécessaire de prévoir quelque part dans votre boucle une condition de sortie, indiquant que la procédure doit s'interrompre sans quoi vous comptez juste sur le windev pour faire le travail et d'expérience, c'est pas la bonne solution. Vous pouvez déclencher cette condition lors de la fermeture de la fenêtre ou de l'application.

    Au pire, vous pouvez utiliser ThreadArrête à la fermeture de votre fenêtre/projet, par contre c'est pas propre, on maîtrise pas l'arrêt, et quand vous allez commencer les écritures sur l'automate ça ne sera pas une option.

    Concernant la forme, est-il vraiment judicieux de faire 15 threads dans votre cas ? d'autant plus que votre thread fait un opération, une pause et rien d'autre.
    Personnellement je ferais les lectures en séquentiel, un automate après l'autre, par exemple :

    1. Lecture automate 1
    2. Threadpause(10)
    3. Lecture automate 2
    4. Threadpause(10)
    5. ...


    (notez l'utilisation de Threadpause)

    Détail concernant votre procédure threadMonitoring, pourquoi lui passer en paramètre l'identifiant pour charger ensuite l'ip et le port dans la fonction ? il serait beaucoup plus propre de directement passer l'adresse et le port en paramètre. Cela vous permettrait surtout de ne pas utiliser les instructions H dans le thread, qui seront à leur tour une nouvelle source de problèmes, regardez du côtés des contextes pour rire.

  3. #3
    Membre averti Avatar de droliprane
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Mai 2005
    Messages
    710
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Vendée (Pays de la Loire)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : Industrie

    Informations forums :
    Inscription : Mai 2005
    Messages : 710
    Points : 444
    Points
    444
    Par défaut
    Ok merci pour vos réponses, mais je n'ai pas tout compris.

    1) Je fais un ThreadArrête uniquement si le thread du même nom est déjà lancé, c'est une sécurité. Bon c'est vrai que s'il est encore en cours, c'est pas plus mal je n'ai pas besoin de le relancer. Mais normalement c'est impossible

    2) Effectivement j'avais fait un Tantque Vrai, sans condition d'arrêt, j'ai simplement mis un booléen que je mets à faux sur fermeture de la fenêtre. De cette façon ça doit empêcher les threads de boucler. Ceci étant ça n'est pas encore ça qui règle le problème. Dans tous les cas, j'ai rajouté sur fermeture de la fenêtre une procédure terminerThreads qui s'appuie sur un tableau d'identifiants de mes threads, et qui ressemble à ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    PROCEDURE terminerThreads()
     
    nomThread est une chaîne
     
    POUR TOUT ELEMENT t DE tabThreads
     
    	nomThread="thread_monitoring"+t
    	SI ThreadEtat(nomThread) = threadEnCours ALORS
    		ThreadArrête(nomThread)
    	FIN
     
    FIN
    Cette procédure met un certains temps pour tuer les theads encours, c'est curieux. Mais ça ne plante plus, en tout cas pas au niveau de l'exécutable, mais dans le GO (test) ça plante toujours

    3) J'ai 15 threads car pour chaque automate j'ai environ une douzaine de variables à lire (peut-être d'avantage à l'avenir), alors je préfère les lire en parallèle dans 15 threads séparés, plutôt que de lire 15x12 données une par une à la suite. La procédure MONITORER contiendra le code de lecture des 12 variables et plus, d'un automate donné. J'ai bien noté l'utilisation de ThreadPause, je vais voir l'impact

    4) Effectivement, je passe maintenant tous les paramètres à threadMonitoring depuis la boucle sur les automates dans chargeModules, c'est moins risqué du fait des contextes threadés qui peuvent ne plus coîncider

    Après ces quelques améliorations de conception, l'appli n'a plus l'air de planter, en exécutable, par contre en mode WDTst je ne peux pas fermer ma fenêtre les threads se libèrent mal ou je ne sais pas bien ce qui se passe mais ça mouline sans fin....
    'Diviser chacune des difficultés en autant de parcelles qu’il se pourrait et qu’il serait requis pour les mieux résoudre', René Descartes

    => Maya GPAO

  4. #4
    Membre averti Avatar de droliprane
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Mai 2005
    Messages
    710
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Vendée (Pays de la Loire)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : Industrie

    Informations forums :
    Inscription : Mai 2005
    Messages : 710
    Points : 444
    Points
    444
    Par défaut
    Une idée qui me vient juste avant de quitter le bureau !!

    Est-ce que je ne peux pas fermer les threads en cours, justement depuis un nouveau thread T spécialement créé pour cette tâche de fermeture, histoire que les ThreadArrete ne soient pas bloquant à la fermeture de la fenêtre ?

    Mais dans ce cas que devient le thread T si je ferme la fenêtre, Est-ce qu'il va se poursuivre et fermer comme il faut les autres threads ?

    Pffff c'est pas simple
    'Diviser chacune des difficultés en autant de parcelles qu’il se pourrait et qu’il serait requis pour les mieux résoudre', René Descartes

    => Maya GPAO

  5. #5
    Membre averti
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2009
    Messages
    178
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2009
    Messages : 178
    Points : 416
    Points
    416
    Par défaut
    Si la procédure avec les ThreadArrête met du temps, c'est que vous n'avez pas réussi à tuer le thread vous même, hors le ThreadArrête ne doit être utilisé que comme un filet de sécurité.

    Pensez à faire une pause après la déclaration de sortie, pour laisser le temps au thread de la lire et de sortir.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ArretThread = vrai
    mutlitache(-MonTemps)
    Vous devez contrôler régulièrement dans votre boucle, entre les différentes lectures si vous devez en sortir. Si vous ne le faites qu'une fois le temps d'attente après la déclaration de sortie doit correspondre au temps d'une boucle.

    Pour les tests, le plus facile reste de faire quelque chose comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
     
    PROCEDURE(MonThread)
     
    BOUCLE
     SI ArretThread ALORS SORTIR
     .........
     SI ArretThread ALORS SORTIR
     .........
     SI ArretThread ALORS SORTIR
     .........
    FIN
     
    Trace("Sortie du thread " + MonThread)
    et de déclencher l'arrêt depuis un bouton. Une fois que vous avez toutes les traces, vous avez résolue votre problème en théorie

  6. #6
    Membre averti Avatar de droliprane
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Mai 2005
    Messages
    710
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Vendée (Pays de la Loire)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : Industrie

    Informations forums :
    Inscription : Mai 2005
    Messages : 710
    Points : 444
    Points
    444
    Par défaut
    Ok, moi mon booléen s'appelle stop_threads, et je le mets à Vrai sur fermeture de la fenêtre.

    Dans ma procédure threadMonitoring j'ai ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
     
    TANTQUE PAS stop_threads
     
    	MONITORER(id, full_ip, port, socket)
     
    	ThreadPause(100)
     
    FIN
    Est-ce que c'est dans MONITORER que je dois aussi tester stop_threads pour sortir plus vite ?

    Merci encore
    'Diviser chacune des difficultés en autant de parcelles qu’il se pourrait et qu’il serait requis pour les mieux résoudre', René Descartes

    => Maya GPAO

  7. #7
    Membre averti
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2009
    Messages
    178
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2009
    Messages : 178
    Points : 416
    Points
    416
    Par défaut
    Tout va dépendre de la durée de votre procédure ...

    Encore une fois, votre objectif est d'interrompre l'exécutions des threads de manière contrôlé, à vous de voir pour place les contrôles de sorties aux endroits stratégiques.
    Si votre procédure enchaîne les lecture sur 15 registres, et que vous ne contrôlez la demande d'arrêt qu'une seule fois par boucle, votre multitâche doit couvrir le temps maximum que met la procédure pour atteindre le contrôle.

    La seule influence sera sur la réactivité de votre application.

  8. #8
    Membre averti Avatar de droliprane
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Mai 2005
    Messages
    710
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Vendée (Pays de la Loire)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : Industrie

    Informations forums :
    Inscription : Mai 2005
    Messages : 710
    Points : 444
    Points
    444
    Par défaut
    Je me rends compte à l'instant que je procède peut-être de la mauvaise façon pour mettre à jour les champs de ma zone répétée (chaque zone correspondant à un automate).

    J'accède en direct à mon objet ZR_BOITES, depuis la procédure qui réalise les lectures et qui est threadée Est-ce que ça peut être la source de mes trop nombreux plantages aléatoires?

    J'imagine que je dois lancer des postmessages à mon thread principal, et que c'est lui qui va modifier l'ihm. Mais comment faire pour passer des postmessage et en même temps des variables (idcase, valeur) ?

    Merci merci
    'Diviser chacune des difficultés en autant de parcelles qu’il se pourrait et qu’il serait requis pour les mieux résoudre', René Descartes

    => Maya GPAO

  9. #9
    Membre averti Avatar de droliprane
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Mai 2005
    Messages
    710
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Vendée (Pays de la Loire)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : Industrie

    Informations forums :
    Inscription : Mai 2005
    Messages : 710
    Points : 444
    Points
    444
    Par défaut
    Bonjour,

    j'essaye tant bien que mal de mettre en place une gestion d'envoi de message structurés depuis mes threads secondaires vers mon thread principal. J'ai créé une classe CMessageIHM, et j'instancie un objet message de cette manière :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    msg est un CMessageIHM 
    msg.id = id   // l'automate concerné
    msg.attribut = "statut"            // l'attribut de la zone répétée que je souhaite affecter
    msg.gauche_droite = "GD"      // si cela concerne la cuve gauche ou droite ou les 2
    msg.valeur = 0                      // la valeur à affecter
    J'envoie l'objet à mon thread principal via PostMessage(Hwnd,"MAJ_IHM", &msg, 0)

    Dans l'initialisation de ma fenêtre FI_MONITORING, je définis la procédure qui gérera l'événement "MAJ_IHM":

    Evénement(JOUER_MESSAGE_IHM,MaFenêtre..Nom,"MAJ_IHM")

    Et le contenu de ma procédure JOUER_MESSAGE_IHM :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    PROCEDURE JOUER_MESSAGE_IHM(_iEvent est un entier,_stParams est un entier,_lParam est un entier=0)
     
    monMessage est un CMessageIHM
     
    Transfert(&monMessage,_stParams,Dimension(monMessage))
     
    Trace("monMessage : "+monMessage.attribut)
    Pour tester, j'ai modifié ma procédure threadée threadMonitoring comme suit :

    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
    PROCEDURE threadMonitoring(LOCAL Hwnd est entier système, id est un entier, full_ip est une chaîne, port est un entier)
     
    msg est un CMessageIHM 
    msg.id = id
    msg.attribut = "statut"
    msg.gauche_droite = "GD"
    msg.valeur = 0
     
    socket est une chaîne = "socket_module_" + id
    SI PAS SocketExiste(socket) ALORS
    	TANTQUE PAS (connexionModule(socket,port,full_ip) OU stop_threads)
    	 	// on boucle
     
    	 	// setStatutModule(id,"GD",0)
    		PostMessage(Hwnd,"MAJ_IHM", &msg, 0)
     
    	 	ThreadPause(100)
    	FIN
     FIN
    A l'exécution, mon thread principal reçoit bien les messages, mais aussi un peu plus que prévu, et c'est ce qui fait planter :



    Un petit tuyau serait le bienvenu (encore).

    Merci à vous
    'Diviser chacune des difficultés en autant de parcelles qu’il se pourrait et qu’il serait requis pour les mieux résoudre', René Descartes

    => Maya GPAO

  10. #10
    Membre averti Avatar de droliprane
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Mai 2005
    Messages
    710
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Vendée (Pays de la Loire)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : Industrie

    Informations forums :
    Inscription : Mai 2005
    Messages : 710
    Points : 444
    Points
    444
    Par défaut
    Bon finalement au lieu de passer un objet je me suis résigné à passer simplement une chaine formattée avec des séparateurs. Je n'ai pas trop de variables (4) alors c'est jouable.
    Je désérialise la chaine dans ma procédure JOUE_EVENEMENT.

    Je n'ai plus de plantage (en exécutable, mais en go test si) et je trouve que les PostMessage mettent quand même du temps, même en local ce n'est pas terrible.

    Je me demandais si je ne pouvais pas faire une communication entre mes threads au travers de sockets. Mes threads écrivent sur un socket, et dans mon thread principal j'ai une boucle infinie qui lit en permanence sur chaque socket... Simple supposition, je ne sais pas si c'est pertinent. En l'écrivant je me rends compte que ce serait des sockets qui servent à lire des infos qui sont déjà lues sur des sockets.... mouai bof

    Enfin j'ai énormément de postmessage à la seconde et je pense que tout ça se congestionne....
    'Diviser chacune des difficultés en autant de parcelles qu’il se pourrait et qu’il serait requis pour les mieux résoudre', René Descartes

    => Maya GPAO

Discussions similaires

  1. mauvaise synchronization des thread
    Par halil.zakaria dans le forum Threads & Processus
    Réponses: 3
    Dernier message: 29/03/2013, 11h11
  2. VS : Fenêtre de suivi des Threads
    Par Arnard dans le forum Framework .NET
    Réponses: 0
    Dernier message: 04/12/2012, 13h05
  3. Réponses: 5
    Dernier message: 30/08/2010, 11h28
  4. Réponses: 3
    Dernier message: 01/10/2007, 11h26
  5. Réponses: 3
    Dernier message: 26/05/2006, 17h35

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