Probleme fermeture de Thread!!!

Résolu
Dryko Messages postés 18 Date d'inscription lundi 18 février 2008 Statut Membre Dernière intervention 24 juillet 2008 - 11 juin 2008 à 11:00
Dryko Messages postés 18 Date d'inscription lundi 18 février 2008 Statut Membre Dernière intervention 24 juillet 2008 - 19 juin 2008 à 09:11
Bonjour,

Je suis en train de programmer une application MFC dans lequel je créer un thread (avec CreateThread) dans le constructeur de ma classe.
Dans le destructeur de ma classe, je detruit (enfin j'essaye c'est la mon probleme) le thread avec TerminateThread.

Mon application marche parfaitement mais lorsque je la ferme, j'ai un gros message d'erreur "L'instruction à "0x00b1234" emploie l'adresse mémoire "0x00b1234". La mémoire ne peut être "read""......... :(

Apres un nombre incalculable de test, j'ai compris que cela venais de la destruction du thread (je ne pense pas que cela vienne de la creation vu qu'il marche tres bien) car si je ne le créé pas, je n'ai pas de pb et si je le créé et que je met seulement une boucle while infinie ca plante!!!...
J'ai beau avoir essayer toute les configurations de fermeture de thread telles :
terminatethread
exit thread
closehandle
getexitcodethread
.....
J'ai essayé tout ca dans tout les sens : tjours la meme erreur!!!!!!

Aidez moi je vous en supplie je vais craquer!!!!!

Merrci d'avance

12 réponses

pipocodesrc Messages postés 29 Date d'inscription lundi 10 janvier 2005 Statut Membre Dernière intervention 16 juin 2008
16 juin 2008 à 09:48
Salut,
La fonction ReceptionImage a obligatoirement une répétition conditionnée de pooling ou autres pour être à l'affut de ce qui arrive ou ce qui dit être envoyé sur ta socket, as-tu la main sur la condition d'arrêt ou est-ce que cela est "enfoui" dans l'api utilisée ?
Dans le 1° cas, créé un destructeur dans CVirtualCamStream et break la condition de ReceptionImage
Dans le 2° cas tu as certinameent une api directshow utilisée pour le stopper.
Estce que tu dois détruire le graph avant ou apres la communication (apres je suppose..) ?
A tous hasards tu peux envoyer le code de la fonction ReceptionImage...
A plus tard
...
3
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
11 juin 2008 à 11:50
TerminateThread est à proscrire en utilisation normale, c'est une fonction d'urgence à n'employer que ponctuellement.

CreateThread est à remplacer par les fonctions MFC.

ciao...
BruNews, MVP VC++
0
pipocodesrc Messages postés 29 Date d'inscription lundi 10 janvier 2005 Statut Membre Dernière intervention 16 juin 2008
12 juin 2008 à 11:08
J'utilise le truc plus bas sans aucun soucis dans une classe perso.
hope this help

class Thread
{
private:
  HANDLE  _handle;
  dword      _idth;
  bool        _created,                       // true is create succesfully
                _exitmainloop;               // used in MainLoop
                _exitthread;
  int         _term_nbtry,_term_wait;  // used for Stop

public:

Thread()
{
_handle   =null;
_created=false;
_exitmainloop=false;
_exitthread=false;
}

bool Create()
{
  _handle = (HANDLE) __beginthreadex       
        (&Thread::STATIC_MainLoop,
         4096,                                // Thread stack size
         this,                                 // Thread start argument
         0,//&sa,                            // Thread security
         CREATE_SUSPENDED,   // Create in suspended state
         &_idth);                            // Thread ID.
 _created=_handle!=INVALID_HANDLE_VALUE;
return _created;
}

//main process
MainLoop()
{
 _exitmainloop=false;
  if (_created) while (!ExitLoop())  { cout<<'.'; Sleep(100); }
 _exitmainloop=true;
 _endthreadex(0);
}

inline bool ExitLoop() { return _exitthread; }

inline bool Created() { return _created; }
inline dword Start () {  return  ResumeThread(_handle); } // fails  if == 0xFFFFFFFF otherwise succeed
inline dword Pause () {  return SuspendThread(_handle);  } // fails  if == 0xFFFFFFFF otherwise succeed
bool Stop (dword ms=250,word nbretry=40)
{
  _term_nbtry=0;
  _term_wait =ms;
  _exitthread=true;           // if stopped when I restart the exitloop returns true



  bool  ok=false;
  dword thstatus;



  if (!_exitmainloop) 
  do
  {
   _waitstatus=WaitForSingleObject (_handle, ms);
   switch (_waitstatus)
    {
    case WAIT_ABANDONED : ok=true; break;
    case WAIT_TIMEOUT   :      break;
    case WAIT_OBJECT_0  : ok=true; break;
    case WAIT_FAILED    : ok=true; break;//can happen if handle is invalid  because already stopped
    //default           : ok=true;       // in other case, exit because an error occurs
    }
   if (!ok)
   {
    if (GetExitCodeThread (_handle, &thstatus))
     if (thstatus == STILL_ACTIVE)
     {
      cout<<endl<<" still active"
    }

   }
  }
  while (++_term_nbtry<nbretry && !ok && !_exitmainloop);



  if (!ok || !_exitmainloop) return false;



  CloseHandle(_handle); //must be called when _exitthreadex( rather _exitthread )
  _handle=null;
  _created=false;



  return true;
}

};
0
Dryko Messages postés 18 Date d'inscription lundi 18 février 2008 Statut Membre Dernière intervention 24 juillet 2008
12 juin 2008 à 11:37
merci pipoco!
je vais tester dans quelques minutes...
mais dis moi : ton code attend que le thread ai fini de tourner ou le programme principal le tue meme si il a pas fini?..
merci
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
pipocodesrc Messages postés 29 Date d'inscription lundi 10 janvier 2005 Statut Membre Dernière intervention 16 juin 2008
12 juin 2008 à 11:46
Il attend qu'il est fini de tourner et que le handle soit libéré par un WaitForSingleObject ...
Si tu ne veux pas attendre utilise Terminate... mais mauvais choix si tu restes dans ton appli sinon l'OS se chargera  de gérer.
Si tu reste dans ton appli il faut que tu testes ExitLoop () dans la répétition du while (!ExitLoop()) ..ou ailleurs qui en dépend.

while (!ExitLoop()) ..
{
  code court ... //pas besoin de tests

  code long ...
  if (ExitLoop ()) break;

....

}
..
0
Dryko Messages postés 18 Date d'inscription lundi 18 février 2008 Statut Membre Dernière intervention 24 juillet 2008
13 juin 2008 à 09:21
encore merci!

Pour le Terminate je sais que ce n'est pas propre mais mon Thread ne s'arrete jamais, c'est au main de lui dire de s'arreter. C'est pourquoi j'ai adopté une méthode basic : j'ai transformé la boucle infinie du thread en while(stop==false) et c'est le main qui passe le bool à true quand il s'arrete.

Mais En fait je me suis aperçu que le probleme ne venait pas de là... En fait, le programme que je vous ai décrit est un filtre DirectShow. J'utilise ce filtre dans une application MFC dans lequel je créé un graphe DirectShow. Lorsque je ferme l'application, il me detruit bien le graphe mais il ne me "detruit" pas le filtre, donc il ne rentre pas dans le destructeur du filtre et donc ne termine pas le thread.
Je sais pas pourquoi le filtre continue a tourner malgré le graphe soit bien detruit... une ptite idée??...

merci d'avance
0
pipocodesrc Messages postés 29 Date d'inscription lundi 10 janvier 2005 Statut Membre Dernière intervention 16 juin 2008
13 juin 2008 à 09:35
Salut, qu'est-ce que vous utilisez comme classe de filtre ? car qui dit exit d'application maîtrisée, dit clean de tout l'environnement (stop engine filter ...) donc arrêt de filtre même en train de processer. Vous vous êtes basé sur un sample du sdk ?
...
0
Dryko Messages postés 18 Date d'inscription lundi 18 février 2008 Statut Membre Dernière intervention 24 juillet 2008
13 juin 2008 à 11:38
Ben en fait c'est un peu compliqué.... même beaucoup
en fait c'est un filtre que j'ai chopé sur le net :
quand le filtre est créé ca créé une classe qui fait pratiquement que le createinstance et qui lui appelle une autre classe qui fait "tout le travailé".... et je pense que la destruction du filtre detruit la premiere classe mais pas la deuxieme..
voila mon .h, si tu veux jeter un oeil :




#include "freeimage.h"
#include
#pragma once






#define DECLARE_PTR(type, ptr, expr) type* ptr = (type*)(expr);






static const GUID CLSID_VirtualCAM;






class CVirtualCamStream;






/**
* @struct thread_param Structure de declaration de thread
* @param cvcs est une classe CVirtualCamStream
* @param soc : socket sur laquelle le programme va recevoir les paquets UDP
*/
struct thread_param{
 CVirtualCamStream* cvcs;
 SOCKET soc;
 MEMOIRE memoire[NOMBRE_MEMOIRE];
};






class CVirtualCam : public CSource
{
public:
    //////////////////////////////////////////////////////////////////////////
    //  IUnknown
    //////////////////////////////////////////////////////////////////////////
    static CUnknown * WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT *phr);
    STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
 






    IFilterGraph *GetGraph() {return m_pGraph;}






private:
    CVirtualCam(LPUNKNOWN lpunk, HRESULT *phr);
};






class CVirtualCamStream : public CSourceStream, public IAMStreamConfig, public IKsPropertySet
{
public:
 
 /**
 * Fonctions d'initialisation et de destruction de socket
 */
 SOCKET CVirtualCamStream::SocketInitialise(SOCKET sock);
 void CVirtualCamStream::SocketDeInitialise(SOCKET sock);
 
 /**
 * Fonction de creation de thread qui permet de faire tourner en parallele la fonction de reception des paquets
 */
 static DWORD WINAPI CVirtualCamStream::ThreadReceptionImage(void *p)
 {
  struct thread_param *Obj = reinterpret_cast<struct thread_param*>(p);
  
  CVirtualCamStream *c = Obj->cvcs;
  return c->ReceptionImage(Obj->soc); 
 }






    //////////////////////////////////////////////////////////////////////////
    //  IUnknown
    //////////////////////////////////////////////////////////////////////////
    STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
    STDMETHODIMP_(ULONG) AddRef() { return GetOwner()->AddRef(); }                                                          \
    STDMETHODIMP_(ULONG) Release() { return GetOwner()->Release(); }






    //////////////////////////////////////////////////////////////////////////
    //  IQualityControl
    //////////////////////////////////////////////////////////////////////////
    STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);






    //////////////////////////////////////////////////////////////////////////
    //  IAMStreamConfig
    //////////////////////////////////////////////////////////////////////////
    HRESULT STDMETHODCALLTYPE SetFormat(AM_MEDIA_TYPE *pmt);
    HRESULT STDMETHODCALLTYPE GetFormat(AM_MEDIA_TYPE **ppmt);
    HRESULT STDMETHODCALLTYPE GetNumberOfCapabilities(int *piCount, int *piSize);
    HRESULT STDMETHODCALLTYPE GetStreamCaps(int iIndex, AM_MEDIA_TYPE **pmt, BYTE *pSCC);






    //////////////////////////////////////////////////////////////////////////
    //  IKsPropertySet
    //////////////////////////////////////////////////////////////////////////
    HRESULT STDMETHODCALLTYPE Set(REFGUID guidPropSet, DWORD dwID, void *pInstanceData, DWORD cbInstanceData, void *pPropData, DWORD cbPropData);
    HRESULT STDMETHODCALLTYPE Get(REFGUID guidPropSet, DWORD dwPropID, void *pInstanceData,DWORD cbInstanceData, void *pPropData, DWORD cbPropData, DWORD *pcbReturned);
    HRESULT STDMETHODCALLTYPE QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD *pTypeSupport);






    //////////////////////////////////////////////////////////////////////////
    //  CSourceStream
    //////////////////////////////////////////////////////////////////////////
    CVirtualCamStream(HRESULT *phr, CVirtualCam *pParent, LPCWSTR pPinName);
    ~CVirtualCamStream();






    HRESULT FillBuffer(IMediaSample *pms);
    HRESULT DecideBufferSize(IMemAllocator *pIMemAlloc, ALLOCATOR_PROPERTIES *pProperties);
    HRESULT CheckMediaType(const CMediaType *pMediaType);
    HRESULT GetMediaType(int iPosition, CMediaType *pmt);
    HRESULT SetMediaType(const CMediaType *pmt);
    HRESULT OnThreadCreate(void);
 HRESULT ShutdownThread( );






private:
    CVirtualCam *m_pParent;
    REFERENCE_TIME m_rtLastTime;
    HBITMAP m_hLogoBmp;
    CCritSec m_cSharedState;
    IReferenceClock *m_pClock;
 FILE* pFile;







 /**
 * @param sock correspond à la socket sur laquelle nous communiquons
 * @param WSAData utile pour la création de la socket
 */
 SOCKET sock;
 WSADATA WSAData;
 






 /**
 * Cette fonction doit être déclarée en static car appelée par un thread
 */
 DWORD ReceptionImage(SOCKET sock);






 HANDLE hthread;
 DWORD hthreadId;
 HANDLE m_hShutdownEvent;

 bool stop;
 
};




encore merci de t'interesser a mon cas ;)
 
0
pipocodesrc Messages postés 29 Date d'inscription lundi 10 janvier 2005 Statut Membre Dernière intervention 16 juin 2008
13 juin 2008 à 17:37
Salut,
Tout destructeur de classe appelle les destructeurs dont il dépend dans l'ordre d'héritage.
Si tu as des classes déclarées et non héritées il faut appeler explicitement celles-ci pour les détruire (sic);
J'ai regardé directshow (en travers), et ai utilisé un sample.
Je pense que cela vient de ton code et de sa structure implantée dans ton prog.
Elle fait quoi la fonction ReceptionImage.
Ton filtre doit s'arrêter, il y a un engine (thread) qui n'est pas stoppé regarde la doc ..., il y a certainement (obligatoirement) une api ou un callback qui permet de stopper l'acquisition/filtrage et de sortitr proprement.
...
0
Dryko Messages postés 18 Date d'inscription lundi 18 février 2008 Statut Membre Dernière intervention 24 juillet 2008
16 juin 2008 à 09:35
Salut, je n'avais pas acces à Internet ce we, c'est pourquoi je n'ai pas pui répondre,

-Pour les destructeurs je suis d'accord mais ma classe CVirtualCam n'en a pas et si j'en créé un, il n'est pas apelé quand je detruit mon graphe DirectShow. :(
-La fonction ReceptionImage communique avec un autre PC et ne s'arrete jamais, c'est quand on detruit le graphe qu'on doit lui dire de s'arreter!
-Pour l'API qui permetterait de tout stopper proprement, là j'avoue que je bloque un peu(beaucoup).

Merci
0
Dryko Messages postés 18 Date d'inscription lundi 18 février 2008 Statut Membre Dernière intervention 24 juillet 2008
17 juin 2008 à 11:28
Salut,
1) Ben en fait le probleme c'est que le programme de rentre jamais dans le destruteur de CVirtualCamStream... parce que au début, il n'y avait pas de condition d'arret dans ReceptionImage (c'etait un while(1)) et j'ai mis en place un bool qui change de valeur dans le destructeur de CVirtualCamStream et qui donc devrait arreter le thread.... mais le destructeur n'est jamais appelé!!!
2) en fait la communication ne s'arrete jamais et j'ai voulu faire un truc pour dire quand on ferme l'application, donc qu'on detruit le graph, ca detruit mon filtre et donc ca change le bool que je t'ai decrit precedement et ca arrete le thread... Pour l'api directshow pour le stopper, j'ai cherché mais g rien trouvé qui pourrait m'aider...

voila la fonction ReceptionImage mais je doute que ca t'aide :

DWORD CVCamStream::ReceptionImage(SOCKET sock)

 /**
 * @param MAX_PACKET_SIZE correspond a la taille d'un buffer receptionnant des donnees par UDP
 * @param buffer est le buffer dans lequel sont stockées les donnees provenant du reseau *
@param compte_reception est un pointeur de reception sur les memoires
 */
 const int MAX_PACKET_SIZE = 65500;
 unsigned char buffer[MAX_PACKET_SIZE] ;
 int compte_reception=0;




  while(1){






    /**
    * @param csin contient les parametres de la socket
    *    @param fin_fichier est mis a 1 par la boucle de reception          pour             signaler    la    fin    d'une image recue
    */
       SOCKADDR_IN csin;
       int fin_fichier=0;  
 
       /**
       * @if Si la mémoire est disponible : on recoit et on ecrit les données dans la       memoire
       */
       if((memoire[compte_reception].flag==true))
        { 
   
         /**
         *          Tant que la fin d'une image n'a pas ete detectee on recoit les paquets
            */
                  while (!fin_fichier){






             /**
             * Reception des paquets contenant les donnees des images
             *             @param n : la fonction recvfrom retourne -1 quand elle recoit rien et la taille             du paquet recu sinon
             */
                int n = -1;
                int sinsize = sizeof (csin);
                while(n<0)
                            {
                                   n = recvfrom(sock,(char*)&buffer,sizeof(buffer),0,(SOCKADDR *)                                    &csin,&sinsize);
                            }
             /**
             *          La fin d'une image JPEG se termine toujours par FF D9, on lit donc          les          deux derniers octets de chaque paquet reçu
                */
                if ((buffer[n-2]==0xff) && (buffer[n-1]==0xd9))
                          {  fin_fichier=1; } 





            /**
            * On signale que la mémoire peut desormais etre affichée en passant flag a false
            * On incrémente le pointeur compte_reception
               */
                  memoire[compte_reception].flag=false;
               compte_reception++;
               if (compte_reception==NOMBRE_MEMOIRE) compte_reception=0;
        }
 
   /**
 * @else Si la memoire n'est pas disponible, on recoit mais on ecrit rien
 */
 else
 {
        /**
        *       Tant que la fin de l'image n'a pas ete detectee, on recoit les paquets
        */
        while (!fin_fichier)
        {    
                int n = -1;
                int sinsize = sizeof (csin);
                while(n<0){
                          n = recvfrom(sock,(char*)&buffer,sizeof(buffer),0,(SOCKADDR *)                        &csin,&sinsize);
                }
             if ((buffer[n-2]==0xff) && (buffer[n-1]==0xd9))
                           {  fin_fichier=1; } 
  }






}
 }
 
  return 0 ;






  }




voila, j'ai mis quelques commentaire pr t'aider a comprendre....
sinon je t'envoie le fichier .c des classes de mon filtre parce que je pense que c'est de là que vient mon probleme :



/**
* La structure permettant d'appeler les threads
* @param p structure de création de thread
*/
struct thread_param p;
//////////////////////////////////////////////////////////////////////////
//  CVirtualCam is the source filter which masquerades as a capture device
//////////////////////////////////////////////////////////////////////////
CUnknown * WINAPI CVirtualCam::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr)
{
    ASSERT(phr);
    CUnknown *punk = new CVirtualCam(lpunk, phr);
    return punk;
}






CVirtualCam::CVirtualCam(LPUNKNOWN lpunk, HRESULT *phr) :
    CSource(NAME("Virtual Cam"), lpunk, CLSID_VirtualCam)
{
    ASSERT(phr);
    CAutoLock cAutoLock(&m_cStateLock);
    // Create the one and only output pin
    m_paStreams = (CSourceStream **) new CVCamStream*[1];
    m_paStreams[0] = new CVCamStream(phr, this, L"Virtual Cam");
}






HRESULT CVirtualCam::QueryInterface(REFIID riid, void **ppv)
{
    //Forward request for IAMStreamConfig & IKsPropertySet to the pin    if(riid _uuidof(IAMStreamConfig) || riid _uuidof(IKsPropertySet))
        return m_paStreams[0]->QueryInterface(riid, ppv);
    else
        return CSource::QueryInterface(riid, ppv);
}






//////////////////////////////////////////////////////////////////////////
// CVirtualCamStream is the one and only output pin of CVirtualCam which handles
// all the stuff.
//////////////////////////////////////////////////////////////////////////








CVirtualCamStream::CVirtualCamStream(HRESULT *phr, CVCam *pParent, LPCWSTR pPinName) :
    CSourceStream(NAME("Virtual Cam"),phr, pParent, pPinName), m_pParent(pParent)
{
/**
* Constructeur du filtre VirtualCAM : met en place l'affichage sous DirectSHow ainsi que la réception par UDP
*/





 /**
 * Appelle la fonction de configuration de l'affichage
 * 640x480x24\25 correspond à 640*480 pixels, 24bits par pixel, 25 images par seconde
 */
 GetMediaType(4, &m_mt);






 /**
 * Mise à 0 des pointeurs d'affichage
 */






 compte_affichage=1;
 compte_affichage_apres=1;






 /**
 * La socket de la structure p est créée par l'appel de la fonction d'initialisation de socket
 * La classe CVCAMStream de la structure p est cette classe elle même
 */
 p.soc=SocketInitialise(sock);
 p.cvcs=this;
 p.memoire[NOMBRE_MEMOIRE]=memoire[NOMBRE_MEMOIRE];






 /**
 * Création du thread de Reception qui va appeler la fonction ReceptionImage
 */
 
 hthread = CreateThread(NULL,0,&CVCamStream::ThreadReceptionImage,&p,0,NULL);





}








CVCamStream::~CVCamStream()
{
 SocketDeInitialise(p.soc);
 WSACleanup();
 TerminateThread(hthread,0);
}




voila pour resumer : la classe CVirtualCam créé une CVirtualCamStream dans sa constructeur mais apres je sais pas comment detruire la classe qu'il vient de construire.....

encore merci pour ton aide!!!
0
Dryko Messages postés 18 Date d'inscription lundi 18 février 2008 Statut Membre Dernière intervention 24 juillet 2008
19 juin 2008 à 09:11
Salut,

en fait c'est bon j'ai trouvé le probleme : je suis un gros c..
Dans ma création de filtre, je déclarais DEUX filtres VirtualCam : un que je mettais dans mon graph et l'autre qui servait à rien mais que je detruisais en detruisant mon filtre... donc le premier continuait a tourner et d'où le thread qui continuait à tourner...
voili voilou la toute petite connerie qui fait perdre des jours de travail..

encore merci pour ton aide!!!
0
Rejoignez-nous