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

Multithreading Discussion :

delete Thread


Sujet :

Multithreading

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 18
    Par défaut delete Thread
    Bonjour, j'ai commencé à programmer il y a pas longtemps en Qt.

    J'utilise un QThread dans un programme qui lance un fichier exterieur.Le programme marche.Mais quand tout est fini et que je veux delete mon QThread j ai droit à un bon crash, pourtant j'attend que tout soit finit(thread et le process)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    test=new Lancem(this,cas); //Création de mon Thread
    spy=new QSignalSpy(test, SIGNAL(finished())); //je surveille si il a fini
     
    ...
    ...
     
    while(spy->count()==0)
    {
          QTest::qWait(250);
    }
    m_pTexB->append(QString("%1").arg(test->isFinished()));
    delete test;
    Je veux faire un delete car sinon chaque fois que je vais lancer un QThread je vais comsommer de la memoire vive pour rien.

    Merci d'avance(en esperant que ma question soit pas trop stupide )

  2. #2
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Par défaut
    salut,

    si j'ai bien compris, la fonction dans laquelle tu fais le 'delete' est en fait un slot, lui-même appelé par un signal du QThread.

    Si c'est le cas, c'est la raison pour laquelle tu as un crash: ton slot (appelons-le mySlot() ) a été appelé en interne par une fonction de QThread (appelons la 'callSlot()'). Or lorsque ton mySlot() retourne, la pile d'exécution retombe dans le code de callSlot(), fonction membre du QThread qui vient d'être détruit. => Crash.

    La solution est de ne pas faire un delete immédiatement mais de le programmer pour un tout petit peu plus tard, le temps que ta pile d'exécution sorte de callSlot(). Une fonction existe pour cela dans la classe QObject (dont dérivent toutes les classes Qt qui ont des signaux/slots) : QObject::deleteLater().

  3. #3
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Par défaut
    Citation Envoyé par Gulish Voir le message
    Si tu declares un parent à ton QThread, le parent, lorsqu il va etre fermé, va détruire tous "ses enfants". Or, si tu as deja détruis un de ces enfants, il va tenter de détruire "un pointeur null", et donc crash.
    C'est doublement FAUX:

    - quand on détruit un objet Qt qui a un parent, il l'avertit automatiquement qu'il ne fait plus partie de la liste des enfants. Donc si j'ai un parent qui a 3 enfants et que je détruit d'abord un des trois enfants puis ensuite le parent lui-même, lors de la destruction du parent il détruira uniquement les deux enfants restant, sans crash.

    - quand on fait un 'delete null', on n'a pas de crash. Simplement le programme ne fait rien. Les deux codes ci-dessous sont strictement équivalents:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    if (myPointer != null) {
        delete myPointer;
    }
    Parfois, il vaut mieux ne rien répondre plutôt qu'induire le posteur du sujet en erreur

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 18
    Par défaut
    Pour la premiere reponse en fait je veux faire un delete avant, je peux pas me permettre le delete du parent vu comme j'ai programmé.

    J ai compris ce que tu viens d'expliquer. Mais le slot ne fait pas parti du QThread.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    connect(test, SIGNAL(exitmess(bool)),this, SLOT(Lancementdel(bool)));
    j'emet un signal quand je quitte, et c'est le parent qui récupere et lance un slot à lui. Donc ton explication marche pas ici(enfin je crois).

    En fait je vais essayer ta fonction deleteLater()

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 18
    Par défaut
    Pour info j'avais testé et je crois que c est faux. Si tu delete le parent en 1er puis le fils ca plante.

    deleteLater() regle le probleme, merci

    En meme temps que je suis la,est ce normal quand je delete QThread je recupere pas toute la memoire vive avant sa création?

  6. #6
    Membre émérite

    Profil pro
    Inscrit en
    Mai 2007
    Messages
    774
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Mai 2007
    Messages : 774
    Par défaut
    Citation Envoyé par nouknouk Voir le message
    C'est doublement FAUX:
    - quand on fait un 'delete null', on n'a pas de crash. Simplement le programme ne fait rien. Les deux codes ci-dessous sont strictement équivalents:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    if (myPointer != null) {
        delete myPointer;
    }
    J'ai vraiment des doutes. Si ce code là marche en release chez toi, je suis sur le c.. :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    int main(int argc, char** argv)
    {
    	QApplication app(argc, argv);
    	QWidget *test = new QWidget();
    	delete test;
    	delete test;
    	return app.exec();
    }
    Et de toute façon, c'est une grave faute de conception que d'essayer de faire un "delete Null".

    G.

  7. #7
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Par défaut
    Citation Envoyé par Keldran Voir le message
    j'emet un signal quand je quitte, et c'est le parent qui récupere et lance un slot à lui. Donc ton explication marche pas ici(enfin je crois).
    Mon assomption sur ton organisation signaux / slots était erronnée, mais le principe reste le même à partir du moment ou dans la chaîne de connexion de signaux / slots qui a amené à exécuter le slot du 'delete' il y a un signal ou un slot qui appartient à l'objet que tu veux détruire.

    Par exemple, le cas s'applique si tu as:
    - un objet QThread qui émet le signal 'tartampion'
    - ce signal est récupéré par un QMonObjet dans son slot 'onTartampion'.
    - le slot 'onTartampion' fais un delete sur l'objet 'monAutreObj'
    - un slot 'onMonAutreObjDetruit', connecté au signal 'monAutreObj::destroyed' est activé
    - 'onMonAutreObjDetruit' fait un delete du QThread.

    On voit ici que 'onMonAutreObjDetruit' ne fait pas partie de QThread, pourtant dans la pile d'exécution on a une suite d'appels successifs qui lient QThread à onMonAutreObjDetruit qui fait le delete :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    QThread::tartampion 
      => QMonObjet::onTartampion 
        => delete monAutreObj
          => monAutreObj::destroyed 
            => onMonAutreObjDetruit 
              => delete QThread

  8. #8
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Par défaut
    J'ai vraiment des doutes. Si ce code là marche en release chez toi, je suis sur le cul :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    QWidget *test = new QWidget();
    delete test;
    delete test;
    Evidemment ce code ne marchera pas ! Mais là tu ne parles plus de la même chose qu'initialement: ici tu parles de faire deux fois un delete sur le même pointeur non nul ; or tu parlais au départ du delete d'un parent après le delete d'un de ses enfants:
    "Si tu declares un parent à ton QThread, le parent, lorsqu il va etre fermé, va détruire tous "ses enfants". Or, si tu as deja détruis un de ces enfants, il va tenter de détruire "un pointeur null", et donc crash."
    Le bon code qui reflète ce que tu disais au départ et qui -selon toi- était faux est:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    QWidget *parent = new QWidget();
    QWidget *child = new QWidget(parent);
    delete child;
    delete test;
    Et ce code là, il passe sans souci !

    Et de toute façon, c'est une grave faute de conception que d'essayer de faire un "delete Null".
    C'est au contraire une erreur de faire un
    ... car tu introduis un check redondant et inutile !

    Donc je persiste et signe, n'en déplaise à ton c..

  9. #9
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Citation Envoyé par Gulish Voir le message
    J'ai vraiment des doutes. Si ce code là marche en release chez toi, je suis sur le cul :
    tu ne met pas test à NULL donc oui il y as un crash. Ceci ne plantera pas
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    QWidget *test = 0;
    delete test
    j'utilise 0 au lieu de NULL car NULL c'est du C et non du C++. Mais bon je chipote.

    Citation Envoyé par Gulish Voir le message
    Et de toute façon, c'est une grave faute de conception que d'essayer de faire un "delete Null".
    oui et non. Tout dépend.
    Pourquoi tester si un pointeur est null si le delete le fait déjà?

  10. #10
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Par défaut
    Citation Envoyé par Keldran Voir le message
    Pour info j'avais testé et je crois que c est faux. Si tu delete le parent en 1er puis le fils ca plante.
    Dans ce sens là (delete parent puis enfant), ça plante car tu essaie de faire un delete sur un pointeur qui pointe vers une zone mémoire déjà libérée, on est d'accord.

    Mais ce qu'avançait Gulish n'était pas la même chose, il parlait de détruire d'abord l'enfant puis le parent:
    Si tu declares un parent à ton QThread, le parent, lorsqu il va etre fermé, va détruire tous "ses enfants". Or, si tu as deja détruis un de ces enfants, il va tenter de détruire "un pointeur null", et donc crash.

  11. #11
    Membre émérite

    Profil pro
    Inscrit en
    Mai 2007
    Messages
    774
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Mai 2007
    Messages : 774
    Par défaut
    "un pointeur null"
    J'ai fait un abus de langage, je voulais dire faire un delete sur un pointeur d'objet déjà détruit (un pointeur qui pointe sur quelquechose qui n'existe plus), d'où le post qui a suivi.

    Concernant la destruction des enfants, tu avais en effet raison. Je me rappelais juste avoir eu un problème du genre, mais en vérifiant j'ai confondu. Il s'agissait d'un problème particulier d'ordre d'appel des constructeurs (constructeur du parent après celui de l'enfant).

    G.

  12. #12
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Par défaut
    Pour en revenir au sujet:

    Citation Envoyé par Keldran Voir le message
    En meme temps que je suis la,est ce normal quand je delete QThread je recupere pas toute la memoire vive avant sa création?
    Pour moi quatre causes potentielles:

    1- soit la mémoire est effectivement libérée, mais tu ne le 'vois' pas (ou pas tout de suite) dans ta mesure de delta de mémoire vive.

    2- soit Qt utilise un système de mémoire cache (ou autre) pour une raison x ou y pour une partie des informations et donc il ne libère pas cette partie de la mémoire en même temps que le thread est déleté (peu probable à priori)

    3- soit tu as une fuite de mémoire provenant de ton code.

    4- soit il y a une fuite de mémoire dans le code de Qt.


    D'où les quatre solutions (respectives) à envisager:

    1- n'oublie pas que le deleteLater ne fait pas le 'delete' immédiatement, mais à la prochaine exécution de la boucle d'événements. Essaie donc de calculer le delta de mémoire dispo un peu plus tard si ce n'est déjà pas le cas.

    2- inspecter le code source de Qt pour y déceler un tel mécanisme, mais franchement j'y crois moyen moins.

    3- L'idée serait de faire le calcul de delta non pas sur un seul thread créé/détruit mais sur la même opération répétée un grand nombre de fois (plusieurs centaines) pour voir si le delta augmente proportionnellement. Si c'est le cas, on est typiquement devant une fuite mémoire. Un outil pour détecter ce genre de chose pourrait t'être utile (genre ValGrind).

    4- achète un ticket de loto, tu as plus de chances de toucher le gros lot

  13. #13
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    J'ajouterai que si t'es sous windows,
    le gestionnaire de tache n'est pas très précis.
    Attention à l'interprétation

  14. #14
    Membre averti
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 18
    Par défaut
    Ouai c est bizarre.Je sais pas comment ils gerent la memoire vive. En fait je lance une liste de programme, desfois la memoire utilisée à la fin ne bouge pas même en attendant un peu et desfois elle diminue beaucoup des qu il a fini la list. Je pense pas avoir de fuite ,enfin j espere. En tout cas merci

  15. #15
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Par défaut
    Une idée comme ça (qui n'est qu'une pure hypothèse de ma part, à vérifier): le système d'exploitation alloue de la mémoire vive aux processus par bloc (page mémoire ?) entier ; il ne la déclare donc comme à nouveau libre que par bloc également et peut-être par un mécanisme asynchrone qui s'exécute "quand le système a du temps libre".

    D'où les libérations par gros blocs et pas toujours juste après que le delete ait été exécuté.

Discussions similaires

  1. Tri multi-threadé
    Par Tifauv' dans le forum C
    Réponses: 8
    Dernier message: 28/06/2007, 09h00
  2. [Kylix] Pb de Thread !!
    Par Anonymous dans le forum EDI
    Réponses: 1
    Dernier message: 25/04/2002, 13h53

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