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

Python Discussion :

Crash aléatoire d'un thread


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    243
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2008
    Messages : 243
    Par défaut Crash aléatoire d'un thread
    Bonjour,

    Depuis plusieurs jours, je suis confronté au crash aléatoire d'un thread dans une application qui comporte:
    1- une fenêtre de saisie et affichage
    2- un thread de calcul.

    Fort heureusement (ou malheureusement!) ces crashs se produisent très rarement; mais cela révèle l'existence d'un bug et j'aimerais bien corriger la situation.

    J'ai reproduit le problème sur un bout de code minimum.

    Le programme principal ouvre une fenêtre Tkinter dans laquelle il y a un curseur (Scale) et un label.

    Ce programme lance un thread de calcul qui tourne continuellement dans une boucle et qui:
    1- récupère la valeur affichée au curseur
    2- calcul une variable, dans le cas présent la variable rejoint progressivement la valeur affichée au curseur
    3- modifie la valeur de la variable dans le "main", ce qui provoque son affichage

    Voici le code du main:

    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
    # -*- coding: ISO8859-1 -*-
    #
    from Tkinter import *
    import threading
    from calcul import *
    import time
     
    from sys import modules
    progmain = modules['__main__']
     
    def afficher(varName, index, mode):  #  déclenchée lors d'un changement de my_var       
        label_my_var.configure ( text = 'ma variable : ' + '%6.1f' %my_var.get())     
     
    def set_var(my_var):  #  activée lors du mouvement du curseur
        my_cursor.event_generate('<Control-Z>')
     
    def stop_calcul():
        calcul_running.set(False)  # stop calcul when mainloop is terminated
        time.sleep (1.)             # attendre 1 seconde l'arrêt du calcul
        root.destroy()
     
    # main prog   ###################################
     
    root = Tk()
    # creation du curseur
    my_cursor = Scale(root, length=450, orient=HORIZONTAL, sliderlength =15,
            label ='ma consigne', from_=0, to=200, tickinterval =20,
            resolution =0.1,showvalue =1, command = set_var)
    my_cursor.pack()
    # creation de l'afficheur avec variable traçable
    label_my_var = Label (root, font=("Arial",14))
    label_my_var.pack()
    my_var = DoubleVar()  
    my_var.trace_variable("w", afficher)  # tout changement de my_var déclenche son affichage
     
    #  lancement du thread de calcul
    calcul_running=BooleanVar()  # le booléen permet d'arrêter le thread
    calcul_running.set(True)
    t1=threading.Thread(target=calcul)
    t1.start()
     
    #  execute mainloop
    root.protocol ("WM_DELETE_WINDOW",stop_calcul)
    root.mainloop()
    Et voici le code du thread de calcul:

    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
    # -*- coding: cp1252 -*-
     
    from math import *
    import time
     
    from sys import modules
    progmain = modules['__main__']
     
    def calcul():
     
    # initialisation
        step = 0.1  ;  temps = 0. ;   var = 0.
     
        while progmain.calcul_running.get()== True:
     
            progmain.my_var.set(var)    #  on renvoie var dans progmain.my_var, cette action déclenche
                                        #  l'affichage par changement de sa valeur
     
    # calcul d'une seconde fictive par pas de 0,1 seconde ################
     
            for i in range(0,10):       
                var0 = progmain.my_cursor.get() # récupérer la valeur du curseur toutes les 0.1 seconde
                temps = temps + step            #  calcul du temps fictif
                dvar = var0 - var               #  adjuster progressivement var à la valeur du curseur
                if (abs(dvar) <=  (5. * step) ) :
                    var = var0
                else :
                    var = var + 5.* step * dvar / abs (dvar)
                time.sleep(0.1)                 # les calculs sont remplacés par time.sleep
    Voici le genre de bug aléatoire qui est déclenché, notez qu'il est surprenant que la fenêtre soit intitulée "Visual C++"



    suivi du message suivant dans lequel la fenêtre est bien intitulée "pythonw.exe - erreur d'application"



    Il n'y a aucun message sur la fenêtre Python !!

    J'ajoute un point important :
    le crash se produit uniquement (quand il se produit!) lors d'un déplacement du curseur

    Merci d'avance à ceux qui me liront et surtout à ceux qui pourront me donner un coup de main pour résoudre ce problème.

    Bonne journée

  2. #2
    Membre émérite
    Homme Profil pro
    Inscrit en
    Décembre 2007
    Messages
    758
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2007
    Messages : 758
    Par défaut
    bonjour,

    as tu essayé de le lancer via python.exe et non pythonw.exe pour voir si un autre message d'erreur avec traceback est affiché sur la console ?

    naïvement, je penserais que le problème viendrait de:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    var0 = progmain.my_cursor.get()
    si jamais l'instruction intervient au moment même où tu fais bouger le curseur. ce qui expliquerait pourquoi le bug est rare et n'intervient que si tu déplace le curseur.

    du coup, ce serait un problème de synchronisation ?

    là je vois 2 idées: passer par une Queue.Queue pour synchroniser ou ajouter un try... except... autour de cette instruction afin d'attendre que le curseur ait arrêté de bouger pour continuer.

    mais compte tenu du message d'erreur que tu as, rien ne laisse présager que ce soit bien ce problème

    le message c++ runtime error n'est pas anormal dans le sens où Python est compilé avec Visual c++ sur windows et qu'il est installé avec quelques dll c++.

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    243
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2008
    Messages : 243
    Par défaut
    Bonjour Kango,

    Merci.

    Je soupçonnais aussi cette instruction depuis un certain temps, pour ne pas dire un temps certain

    Et tu as raison

    Je ne connais pas grand'chose à Python et je ne pensais pas que python.exe donne plus d'infos que pythonw.exe ...

    Donc voici le message de python.exe :
    on voit bien que le pb est sur cette ligne



    J'ai essayé try ... except ... et j'ai cru pendant 5 minutes que cela marchait mais non

    Maintenant, je suis nul alors j'ai fait ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    try : progmain.my_var.set(var)    
    except : pass
    Il faut peut-être détecter l'erreur ???

    Si tu as le temps, peux tu, stp, m'en dire un peu plus sur les Queue.Queue ?



    A+

  4. #4
    Membre émérite
    Homme Profil pro
    Inscrit en
    Décembre 2007
    Messages
    758
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2007
    Messages : 758
    Par défaut
    ok, Queue.Queue est un peu plus lourd à mettre en place, et pas vraiment adapté à ton problème,

    je te propose plutôt un truc du genre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    while 1:
        try:
            var0 = progmain.my_cursor.get()
        except ValueError:
            time.sleep(0.01)
        else:
            break
    qui va rendre l'appel bloquant: c'est à dire qu'il va attendre que tu arrêtes de bouger pour récupérer la valeur.

    une autre approche consiste à conserver la valeur de var0 de l'itération précédente:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    oldvar0 = var0
    try:
        var0 = progmain.my_cursor.get()
    except ValueError:
        var0 = oldvar0

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    243
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2008
    Messages : 243
    Par défaut
    Merci Kango,

    ça a l'air de fonctionner

    J'apprécie ce forum, il y a vraiment des gens qui savent !

    Bonne journée

    PS : je ne mets "résolu" car je n'ai pas testé encore assez longtemps

  6. #6
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Bonjour,

    Intéressent...
    Cela montre t'il que dans la class variable tk la variable est vidée (none) pour prendre la nouvelle valeur ? Je n'ai rien vu de ce type dans Tkinter.py.
    Cela viens t'il de Tk ?

    Une idée ?

    @+

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

Discussions similaires

  1. [JFileChooser] plantage aléatoire dans un Thread séparé
    Par RR instinct dans le forum Agents de placement/Fenêtres
    Réponses: 3
    Dernier message: 24/07/2009, 13h53
  2. dRedimensionne crash aléatoires
    Par xander412 dans le forum WebDev
    Réponses: 0
    Dernier message: 17/07/2009, 15h13
  3. [Ubuntu 8.10][Eclipse 3.2] Crash aléatoire très régulier
    Par ovh dans le forum Applications et environnements graphiques
    Réponses: 7
    Dernier message: 09/03/2009, 23h08
  4. Réponses: 10
    Dernier message: 11/01/2008, 11h10
  5. Crash aléatoires dans un programme quasi-totallement managé
    Par smyley dans le forum Général Dotnet
    Réponses: 1
    Dernier message: 09/11/2007, 02h22

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