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

MFC Discussion :

Fermeture de thread


Sujet :

MFC

  1. #1
    Membre à l'essai
    Inscrit en
    Avril 2004
    Messages
    25
    Détails du profil
    Informations forums :
    Inscription : Avril 2004
    Messages : 25
    Points : 18
    Points
    18
    Par défaut Fermeture de thread
    Bonjour,

    Je vous écris afin de faire part d'un soucis dans l'un des tutos (et vous expliquer mon problème qui persiste :p) :
    http://c.developpez.com/faq/vc/?page...opWorkerThread
    Celui-ci consiste en l'arrêt d'un Thread MFC via l'utilisation "propre" des Handlers.

    J'ai une appli MFC basé sur une CDialog. J'ai voulu mettre le tuto en place car j'ai un soucis (qui persiste) lorsque je veux arreter un thread en cours quand la CDialog est fermé.
    J'arrive a fermer convenablement le thread lors d'un clic sur un bouton, mais pas lors de la fermeture de l'appli. Dans ce deuxième cas, j'ai un memory leak.

    Dans votre tuto, vous déclarez deux fois des HANDLE. Certains en membres de la classe et d'autres dans le constructeur. Les premiers n'étant pas utilisés après.
    Il me reste un problème concernant l'application de ce tuto : Si je suis le tuto à la lettre, le thread se termine bien, mais le
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ::WaitForSingleObject(m_hWaitThread, INFINITE);
    bloque l'appli malgré la présence de :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    if(::WaitForSingleObject(pView->m_hEndThread, 0) == WAIT_OBJECT_0)
    {			
    	pView->m_sText = "Calcul annulé.";
    	::PostMessage(hWnd, MY_WM_UPDATE, (WPARAM)0, (LPARAM)0);
    	pView->m_cRatio.EnableWindow(true);
    	pView->m_bThread = false;
    	::SetEvent(pView->m_hWaitThread);
    	return result;
    }

  2. #2
    Membre confirmé Avatar de stephdim
    Profil pro
    Inscrit en
    Août 2007
    Messages
    462
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 462
    Points : 521
    Points
    521
    Par défaut
    Bonjour,

    Effectivement il y a une petite erreur dans le tuto, je confirme ...

    Juste pour etre sure que l'evenement m_hWaitThread soit bien positionné:

    Remplacer

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ::SetEvent(pView->m_hWaitThread);
    par

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    VERIFY(::SetEvent(pView->m_hWaitThread));
    Et executer l'appli en mode DEBUG

    Il y a aura une assertion si SetEvent() échoue. (mauvais handle par ex ..., ou le CreateEvent() a echoué par ex)


    @+

  3. #3
    Membre à l'essai
    Inscrit en
    Avril 2004
    Messages
    25
    Détails du profil
    Informations forums :
    Inscription : Avril 2004
    Messages : 25
    Points : 18
    Points
    18
    Par défaut
    Merci du conseil (que j'ai appliqué). Je n'ai pas eu d'assertion.

    Il est a noter que j'ai deux moyens de demander l'arret du thread :
    - un bouton stop
    - ferme l'appli (le X en haut à droite de toute appli fenétrée windows :p )

    Si je ne met pas le "WaitForSingleObject" :
    Dans le 1er cas, je vois que le thread se termine nikel dans la fenetre Output. (sauf que j'attends pas proprement la fermeture du thread)
    Dans le 2eme cas, j'ai un memory leak d'un thread.
    Si je met le "WaitForSingleObject", dans les deux cas, j'ai mon appli bloquée...

    Si vous avez besoin d'autres parties du code... la j'ai cherché un peu partout et appliqué plusieurs tutos... j'comprends pas ce qu'il attend :s

  4. #4
    Membre confirmé Avatar de stephdim
    Profil pro
    Inscrit en
    Août 2007
    Messages
    462
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 462
    Points : 521
    Points
    521
    Par défaut
    Ben j'ai du mal a voir sans voir l'implementation réelle. Le tuto lui il marche

    Peux tu poster la partie qui créé le thread, signale l'arret et le corps du thread. (la boucle) --> ça c'est la partie debuggage

    Sinon je peux t'indiquer d'autres methodes plus ou moins simple.

    Tu peux faire pour créer ton thread:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    m_hEndEvent=CreateEvent(NULL,TRUE,FALSE,NULL);   // l'évènement pour commander le suicide du thread (m_hEndEvent=HANDLE)
    VERIFY(m_hEndEvent!=NULL);     // le mieux serait un vrai test et un message d'erreur
    m_pThread=AfxBeginThread(proc,param,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED,NULL);    // création du thread mais suspendu (m_pThread=CWinThread*)
    VERIFY(m_pThread!=NULL);     // pareil un vrai test c'est mieux
    m_pThread->m_bAutoDelete=FALSE;     // pas d'auto-destruction de CWinThread
    m_pThread->ResumeThread();   // on démarre le thread
    Pour le détruire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    VERIFY(SetEvent(m_hEndEvent));       // suicide du thread
    VERIFY(WaitForSingleObject(m_pThread->m_hThread,INFINITE)==WAIT_OBJECT_0);    // attendre que le thread soit mort
    delete m_pThread;       // on peut detruire CWinThread
    CloseHandle(m_hEndEvent);     // on n'a plus besoin de l'evenement
    Dans le thread, suffit de vérifier l'evenement m_hEndEvent :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    if (WaitSingleObject(hEndEvent,0)==WAIT_OBJECT_0)    // suicide ?
        return "code retour";           // on sort de la procedure

    Ca devrait marcher, grosso-modo c'est pareil que le tuto, on economise un "Event".

    En faisant WaitForSingleObject(m_pThread->m_hThread,INFINITE); la fonction rend la main qd le thread est fini ou tout de suite s'il est déjà mort.
    Pas de risque de blocage

    @+

  5. #5
    Membre confirmé Avatar de stephdim
    Profil pro
    Inscrit en
    Août 2007
    Messages
    462
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 462
    Points : 521
    Points
    521
    Par défaut
    Tu peux encore simplifier en remplaçant l'evenement par un simple booleen. (ça fait pas très academique, mais c'est vrai que dans ce contexte là c'est du luxe )

    Ca donnerait:

    La création:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    m_StopThreadFlag=false;      // c'est un bool
     
    m_pThread=AfxBeginThread(proc,param,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED,NULL);
    m_pThread->m_bAutoDelete=FALSE;
    m_pThread->ResumeThread();
    L'arret:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    m_StopThreadFlag=true;
    WaitForSingleObject(m_pThread->m_hThread,INFINITE);
    delete m_pThread;
    Dans la boucle du thread:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    if (ptr->m_StopThreadFlag)
       return "code retour";
    c'est encore plus simple et ça marche très bien si tu manipules le bool que de false vers true depuis n'importe quel autre thread.

    voila

    @+

  6. #6
    Membre à l'essai
    Inscrit en
    Avril 2004
    Messages
    25
    Détails du profil
    Informations forums :
    Inscription : Avril 2004
    Messages : 25
    Points : 18
    Points
    18
    Par défaut
    J'ai essayé un peu toutes les combisaisons avec les bool et les events.
    Ce que je constate c'est que mon thread se termine bien lorsque j'utilise mon bouton "stop", mais pas lors d'une fermeture de l'appli en cours de route.

    J'ai fait un essai :
    J'ai mis un AfxMessageBox lors de la fermeture afin de vérifier que tout était bien appelé (on doute de tout dans ces cas la :p).
    J'ai bien ma fenetre qui pop et hoo miracle, mon thread se ferme à ce moment la. Donc mettre un WaitForSingleObject ou un sleep(10000) ca ne fonctionne pas, mais un AfxMessageBox... si.
    Je me demande ce que fait l'AfxMessageBox en "arrière plan" qui manque à la libération normale de mon thread.

    A savoir (pour completer), que pour intercepter la fermeture de l'appli j'intercepte le message WM_CLOSE.

  7. #7
    Membre à l'essai
    Inscrit en
    Avril 2004
    Messages
    25
    Détails du profil
    Informations forums :
    Inscription : Avril 2004
    Messages : 25
    Points : 18
    Points
    18
    Par défaut
    Bon, je me suis repenché sur la question et j'ai repris les tutos. Le fait de mettre l'arret dans le OnClose (message WM_CLOSE) m'avait mis un doute sur le moment ou la dialog libère ses variables etc.

    j'ai donc remis, comme dans le tuto, l'arrêt du thread dans le destructeur de ma CDialog :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    CDialogDlg::~CDialogDlg()
    {
    	if(m_bThread == true) {
    		::SetEvent(m_hEndThread);
    		::WaitForSingleObject(m_hWaitThread, INFINITE);
    		Sleep(500);
    	}
    	::CloseHandle(m_hEndThread);
    	::CloseHandle(m_hWaitThread);
     
    }
    Comme vous voyez, j'ai mis un pôtit Sleep de 500ms pour rire après avoir attendu l'event de fin de thread... ca marche.
    En fait, je pense que le debugguer de Visual détecte la fermeture de ma CDialog pour déterminer les memory leaks... mais il se peut que le thread n'ai pas fini de libérer sa mémoire. (après la levée de l'event, il reste le return à faire et à s'auto-terminer au thread.

    Enfin, il me fait plus de memory leak si je laisse le sleep.

  8. #8
    Membre confirmé Avatar de stephdim
    Profil pro
    Inscrit en
    Août 2007
    Messages
    462
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 462
    Points : 521
    Points
    521
    Par défaut
    Le OnClose() est seulement appelé quand on ferme la fenetre par la croix ou Alt+F4. Il ne sera pas appelé si survient un DestroyWindow. (je suppose que c'est un dialogue modeless)

    --> Je placerais tout ça plutot dans OnPostNcDestroy.

    @+

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

Discussions similaires

  1. Fermeture de thread impossible
    Par cbegood dans le forum Windows Forms
    Réponses: 2
    Dernier message: 13/10/2008, 10h28
  2. Fermeture de thread/Stopper recvfrom
    Par homeostasie dans le forum Visual C++
    Réponses: 7
    Dernier message: 17/11/2006, 09h59
  3. [C#] - Problème sur fermeture d'un thread
    Par Erakis dans le forum Windows Forms
    Réponses: 4
    Dernier message: 27/01/2006, 01h22
  4. Probleme fermeture Thread
    Par Raton dans le forum MFC
    Réponses: 4
    Dernier message: 29/09/2005, 09h51
  5. [Thread][socket]Problème de fermeture d'un thread
    Par meda dans le forum Concurrence et multi-thread
    Réponses: 4
    Dernier message: 04/11/2004, 01h03

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