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

Threads & Processus C++ Discussion :

[thread] Nettoyage après la fin d'un thread


Sujet :

Threads & Processus C++

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2008
    Messages : 10
    Par défaut [thread] Nettoyage après la fin d'un thread
    Bonjour,
    je développe une classe C++ pour gérer les threads (interfaçant les API WIn32).
    J'aurai besoin de plusieurs petites précisions pour le nettoyage à faire après la fin d'un thread et de l'utilisation de l'API CloseHandle.

    1. Après le kill d'un thread par l'API "TerminateThread", est-il nécessaire d'utiliser CloseHandle sur le handle du thread ?

    2. Le thread se termine de lui-même (il a terminé ce qu'il avait à faire) peut-il lui-même appelé la fonction CloseHandle juste avant de terminer ?

    Exemple :
    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
    // Launch-Start thread
    HANDLE	classThread::launch(void)
    		{
    		if(this->status != THREAD_NOT_RUNNING)		return this->handle;
     
    		// Create thread & return handle
    		this->handle	= CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)_threadFn, (LPVOID)this, NULL, &this->_id);
     
    		return this->handle;
    		}
     
    // Main thread function
    UINT32	classThread::_threadFn(void * lParam)
    		{
    		classThread &thread = (classThread&)lParam;
     
    		// Change status
    		thread.status		= THREAD_RUNNING;
     
    		// Execute main function
    		thread.mainFn();
     
    		// Clean up
    		CloseHandle(thread.handle);
    		thread.handle  = NULL;
     
    		// Change status
    		thread.status		= THREAD_NOT_RUNNING;
     
    		return 0;
    		}
    Merci.

  2. #2
    screetch
    Invité(e)
    Par défaut
    etant donné les problemes de leak engendrés par terminatethread, je ne vois pas pourquoi tu te soucies du handle. Ton thread a probablement oublié de relacher sa mémoire, voire même un mutex...

    quant à closehandle sur lui même, je pense que c'est possible, mais je ne suis pas certain.

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2008
    Messages : 10
    Par défaut
    Etant donné que le thread est encapsulé dans une classe, je n'ai aucun problème de fuite mémoire si je tue le thread avec TerminateThread.

    La fonction principale du thread au pire des cas fait des réallocation mémoire, donc si le thread ne sort pas proprement, le destructeur de la classe se chargera de faire le ménage ainsi que le déverrouillage de tous les éléments nécessaires à la synchronisation.

    On peut très bien imaginer le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    pThread = new classThread();// Appel au constructeur - allocation mémoire
     
    pThread->launch();// Boucle principale, calculs longs
    pThread->kill();// Kill - sortie aléatoire dans le thread
     
    delete pThread;// Appel au destructeur - libération mémoire - dévérouillage des mutex et autres
    Comme j'ai besoin de réactivité et que la boucle principale fait des calculs longs, je veux avoir une fonction de kill sous la main qui me donne le plus de réactivité possible, mais ce n'est pas pour autant que je veux laisser le souk en mémoire (d'où l'utilisation de CloseHandle).

  4. #4
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Etant donné que le thread est encapsulé dans une classe, je n'ai aucun problème de fuite mémoire si je tue le thread avec TerminateThread
    Ça ça me semble très vite dit.

    Sinon, d'après la doc, il faut que tu fermes le handle explicitement (même si ce n'est pas explicite dans la doc).

  5. #5
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2008
    Messages : 10
    Par défaut
    Alors normalement, j'utilise une classe dérivée de la classe classThread de cette manière :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class classThreadDecoder : public classThread
    	{
    	// Blabla
    	}
    Et je fais les allocations ainsi que les libérations de ce qui est utilisé dans la boucle principale du thread dans le constructeur et le destructeur :
    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
    classThreadDecoder::classThreadDecoder(void)
    	{
    	this->decoder		= new classDecoder();
    	}
     
     
    classThreadDecoder::~classThreadDecoder(void)
    	{
    	if(this->decoder)	delete this->decoder;
    	}
    /* CONSTRUCTOR-DESTRUCTOR */
     
     
    /* OTHER FUNCTIONS */
    void		classThreadDecoder::mainFn(void)
    	{
    	UINT64		itemToCompute;
     
    	itemToCompute = this->decoder->getItemValue();
     
    	this->decoder->decode(itemToCompute);
    	}
    Est ce que la variable itemToCompute peut constituer une fuite mémoire si je tue mon thread comme un sauvage ?
    Et est ce que les variables internes utilisées dans par exemple les fonctions decoder::getItemValue() ou decoder::decode() peuvent être des fuites mémoires ?
    Sachant que je vais appeler ensuite les destructeurs et que je vais utiliser CloseHandle sur les thread

  6. #6
    screetch
    Invité(e)
    Par défaut
    TerminateThread va tuer le thread, quelque soit l'opération qu'il faisait, et ne pas nettoyer la pile. Si ton thread avait un lock sur un fichier ou un lock sur un mutex, il ne pourra pas le relacher. Bien que ta classe Thread ne cause pas de leak, ton thread lui même et la fonction qui s'y executait va mourir dans d'atroces souffrances et polluer ta mémoire.

  7. #7
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Juin 2006
    Messages
    85
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 85
    Par défaut
    Citation Envoyé par screetch Voir le message
    TerminateThread va tuer le thread, quelque soit l'opération qu'il faisait, et ne pas nettoyer la pile. Si ton thread avait un lock sur un fichier ou un lock sur un mutex, il ne pourra pas le relacher. Bien que ta classe Thread ne cause pas de leak, ton thread lui même et la fonction qui s'y executait va mourir dans d'atroces souffrances et polluer ta mémoire.
    Pas mieux dit. C'est pas terrible d'arrêter un thread long en cours.

    Par contre pour arrêter un thread qui boucle, il est possible d'utiliser un flag "testé" à chaque boucle :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    	pMyThread->m_bShutnown = false;
    	while(!m_bShutdown)
    	{
    		// Mon traitement
    	}
    Pour tuer le trhread il suffit de flaguer quelque part dans le code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    	pMyThread->m_bShutnown = true;
    A la boucle suivante, tu sors de la fonction et ton thread se termine tout seul.

    Dans ton cas (le long thread) tu pourrais peut-être rajouter régulièrement un test

    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
     
    	pMyThread->m_bShutnown = false;
     
    	// Traitement partie 1
     
    	if(m_bShutdown)
    	{
    		// Désallocation des variables
    		return;
    	}
     
    	// Traitement partie 2
     
    	if(m_bShutdown)
    	{
    		// Désallocation des variables
    		return;
    	}
     
    	...

  8. #8
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 394
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 394
    Par défaut
    La doc de TerminateThread() est assez explicite quand il s'agit de déconseiller son utilisation.

    Quant à la fermeture de handle, elle est indépendante de la fin du thread: Le handle n'est pas fermé automatiquement quand le thread se termine, et fermer un handle ne tue pas le thread.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  9. #9
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2008
    Messages : 10
    Par défaut
    Pour la méthode "propre", il n'y a aucun problème de scruter une variable et de tester si elle a la bonne valeur pour arrêter le thread.
    Mais cette méthode manque cruellement de réactivité... actuellement le thread appelle une fonction de traitement d'image (que je ne maitrise pas) qui peut prendre quelques secondes, d'où l'utilisation de terminateThread.

    Si quelqu'un à une idée pour stopper un thread de manière rapide (plus rapide que la scrutation d'une variable) et en laissant l'endroit le plus propre possible, je suis preneur !!!!

  10. #10
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2008
    Messages : 10
    Par défaut
    Voici le code de la méthode que j'implémente actuellement pour gérer + ou - l'arrêt d'un thread :
    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
    45
    46
    47
    48
    49
    // Thread management //
    void	classThread::_cleanUp(void)
    			{
    			// Close thread handle		
    			if(this->_handle != NULL)	CloseHandle(this->_handle);
     
    			this->_handle	= NULL;
    			}
     
    void	classThread::stop(pipelineServer::UINT8 forceKill, pipelineServer::UINT32 maxDelay)
    			{
    			// Verif
    			if(this->status	== THREAD_EXITED)				return;
    			if(this->status	== THREAD_PAUSED)				this->resume();	// WakeUp thread
     
    			if(forceKill)
    				{
    				// Kill thread ? (hard method)
    				this->kill();
    				}
    			else
    				{
    				// Try to terminate thread (smooth method :) )
    				this->status		= THREAD_CANCELED;
     
    				try
    					{	this->onStop();	}
     
    				catch(...)
    					{}
     
    				this->waitForTermination(maxDelay);
    				}
    			}
     
     
    void	classThread::kill(void)
    			{
    			// Verif
    			if(this->status	== THREAD_EXITED)				return;
     
    			// Terminate thread
    			if(this->_handle != NULL)	TerminateThread(this->_handle, 0);
     
    			this->_cleanUp();
     
    			// Change status
    			this->status				= THREAD_EXITED;
    			}
    Voici la fonction principale du thread (les fonctions onBegin, entry et onEnd sont virtuelles), la scrutation de la variable se fait dans la fonction entry :
    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
    void	classThread::mainFn(void)
    			{
    			// Change status
    			this->status		= THREAD_RUNNING;
     
    			// Execute event function "onBegin"
    			try
    				{	this->onBegin();	}
     
    			catch(...)
    				{}
     
    			// Execute main function
    			try
    				{	this->entry();	}
     
    			catch(...)
    				{}
     
    			// Execute event function "onEnd"
    			try
    				{	this->onEnd();	}
     
    			catch(...)
    				{}
     
    			// Clean up
    			this->_cleanUp();			 
     
    			// Change status
    			this->status		= THREAD_EXITED;			
    			}

  11. #11
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Si quelqu'un à une idée pour stopper un thread de manière rapide (plus rapide que la scrutation d'une variable) et en laissant l'endroit le plus propre possible, je suis preneur !!!!
    Passe par un process externe (en communiquant en shared mem, ipc ou autre), plutôt qu'un thread. Les deux seront donc correctement isolés, et la fermeture brutale de l'un ne corrompra pas l'autre.

    Les systèmes d'exploitation modernes sont largement meilleurs que ce que tu feras pour nettoyer les résidus.

Discussions similaires

  1. [Débutant] Lancer une Thread après la fin de deux autres
    Par Zarrows dans le forum C#
    Réponses: 12
    Dernier message: 10/02/2012, 14h43
  2. [Thread] pb apres arret d'un thread
    Par titiyo dans le forum Langage
    Réponses: 5
    Dernier message: 20/02/2006, 10h11
  3. [C#] Fin d'un Thread
    Par maitrebn dans le forum C#
    Réponses: 2
    Dernier message: 18/11/2005, 10h56
  4. [Thread] comment attendre la fin d'un thread?
    Par billynirvana dans le forum Concurrence et multi-thread
    Réponses: 11
    Dernier message: 24/08/2005, 10h43
  5. [MFC]Détection de la fin d'un thread
    Par Oberown dans le forum MFC
    Réponses: 17
    Dernier message: 25/08/2004, 11h51

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