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

Windows Discussion :

PostThreadMessage trop tot après CreateThread


Sujet :

Windows

  1. #1
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Points : 1 051
    Points
    1 051
    Par défaut PostThreadMessage trop tot après CreateThread
    Je viens de me heurter à un deadlock avec ce programme :

    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
    #include <Windows.h>
    
    DWORD WINAPI EntryPoint( void * )
    {
    	MSG msg;
    	while ( GetMessage( &msg, NULL, 0, 0 ) )
    	{
    	}
    
    	return 0;
    }
    
    int WINAPI WinMain( HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPSTR lpCmdLine,
        int nCmdShow )
    {
    	DWORD id;
    	HANDLE th = CreateThread( NULL, 0, EntryPoint, NULL, 0, &id );
    		
    	//Sleep( 1000 );
    
    	PostThreadMessage( id, WM_QUIT, 0, 0 );
    	
    	WaitForSingleObject( th, INFINITE );
    }
    Le thread créé ne reçoit jamais mon message.
    Il suffit que je décommente le Sleep pour que je reçoive toujours mon message.

    Alors je me demande dans quelle mesure mon thread est créé s'il n'est pas cappable de recevoir mes messages... Rien n'est dit sur la msdn. Cela m'oblige à instaurer un mécanisme d'attente pour être sûr que mon thread est arrivé à la boucle des messages avant de lui en envoyer.

  2. #2
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Points : 50 367
    Points
    50 367
    Par défaut
    Dans Winmain, tu créé un event, tu créé ton thread et tu te met en attente bloquante (ou avec timeout) sur ton event.

    Quand ton thread est parti, il signale ton event (cela doit être une variable globale à Winmain et à ton thread ou alors une variable du contexte du thred).

    Winmain est libéré, il peut détruire l'event (plus utile) et poster le message au thread.
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  3. #3
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Points : 1 051
    Points
    1 051
    Par défaut
    C'est ce que j'ai essayé mais visiblement, ça ne marche que 10 fois sur 11. J'arrive quand même à des deadlock avec ce code :

    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
    #include <Windows.h>
    
    HANDLE hevent;
    
    DWORD WINAPI EntryPoint( void * )
    {
    
    	SetEvent( hevent );
    
    	MSG msg;
    	while ( GetMessage( &msg, NULL, 0, 0 ) )
    	{
    	}
    
    	return 0;
    }
    
    int WINAPI WinMain( HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPSTR lpCmdLine,
        int nCmdShow )
    {
    	hevent = CreateEvent( NULL, TRUE, FALSE, NULL );
    
    	DWORD id;
    	HANDLE th = CreateThread( NULL, 0, EntryPoint, NULL, 0, &id );
    	
    	WaitForSingleObject( hevent, INFINITE );
    
    	PostThreadMessage( id, WM_QUIT, 0, 0 );
    	
    	WaitForSingleObject( th, INFINITE );
    }
    Etrange non ? Il semblerait que même une fois rentré dans EntryPoint, la file de message ne soit pas fiable.

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Fais un PeekMessage() avec le flag PM_NOREMOVE au début de ton thread, AVANT le SetEvent().
    Ainsi, tu seras sûr que la file de messages correspondant au thread a été créée (elle n'est créée que lors du premier appel à une fonction qui s'y rapporte).

    PS: À ta place, j'utiliserais WaitForMultipleObjects() sur l'event et le thread, histoire de choper une fin anormale du thread (même si ce n'est pas censé arriver).
    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.

  5. #5
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Points : 1 051
    Points
    1 051
    Par défaut
    Très bonne idée le peekmessage

    elle n'est créée que lors du premier appel à une fonction qui s'y rapporte
    C'est documenté quelque part ? je n'ai pas trouvé dans la msdn.

    Et oui, tu as raison pour le wait multiple.


    En fait je suis en train de recoder un truc que j'avais fait il y a un peu plus d'un an maintenant, mais que j'ai bêtement perdu...

    Et au fur et à mesure, les souvenirs me reviennent (de mauvais souvenirs) sur la fiabilité de PostThreadMessage.

    Il me semble me rappeller que même une fois bien lancé, si on envoie au thread plusieurs messages à la volée consécutivement, il se peut qu'il en perdre quelques uns au passage...

    Du coup j'avais réimplémenté ma propre file de message, basée sur un conteneur standard encapsulé par des sections critiques. Et la je recevait bien tous mes messages d'un thread à l'autre.

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Citation Envoyé par NiamorH
    C'est documenté quelque part ? je n'ai pas trouvé dans la msdn.
    Ahem! Doc de PostThreadMessage()
    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.

  7. #7
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Points : 1 051
    Points
    1 051
    Par défaut
    merde, j'ai pas vu !

    En tout cas j'ai plus de soucis de deadlock avec l'ajout de la ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE );
    Merci!

  8. #8
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Points : 1 051
    Points
    1 051
    Par défaut
    Avec ce code, jusqu'à NBMESSAGES = 6000 tou va bien, mais au dessus les messages se perdent.

    Bon j'aurais surement rarement l'occasion d'en envoyer autant comme ça dans une appli de toute manière...

    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
    50
    51
    52
    53
    54
    #include <Windows.h>
    
    HANDLE hevent;
    int nb = 0;
    int NBMESSAGES = 7000;
    
    DWORD WINAPI SenderThread( void * idMainThread )
    {
    	DWORD id = (DWORD)idMainThread;
    
    	for ( int i = 0; i < NBMESSAGES; ++i )
    		PostThreadMessage( id, WM_USER+100, 0, 0 );
    
    	return 0;
    }
    
    DWORD WINAPI MainThread( void * )
    {
    	MSG msg;
    	PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE );
    
    	SetEvent( hevent );
    
    	while ( GetMessage( &msg, NULL, 0, 0 ) )
    	{
    		if ( msg.message == WM_USER+100 )
    			++nb;
    	}
    
    	return 0;
    }
    
    int WINAPI WinMain( HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPSTR lpCmdLine,
        int nCmdShow )
    {
    	hevent = CreateEvent( NULL, TRUE, FALSE, NULL );
    
    	DWORD id, id1, id2;
    	HANDLE th = CreateThread( NULL, 0, MainThread, NULL, 0, &id );
    	
    	WaitForSingleObject( hevent, INFINITE );
    
    	HANDLE thrds[2];
    	thrds[0] = CreateThread( NULL, 0, SenderThread, (LPVOID)id, 0, &id1 );
    	thrds[1] = CreateThread( NULL, 0, SenderThread, (LPVOID)id, 0, &id2 );
    
    	WaitForMultipleObjects( 2, thrds, TRUE, INFINITE );
    
    	PostThreadMessage( id, WM_QUIT, 0, 0 );
    	
    	WaitForSingleObject( th, INFINITE );
    }

  9. #9
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Points : 50 367
    Points
    50 367
    Par défaut
    Peut être que tu pourrait tester le code de retour de PostThreadMessage()
    Citation Envoyé par la doc MSDN
    Return Value

    If the function succeeds, the return value is nonzero.

    If the function fails, the return value is zero. To get extended error information, call GetLastError. GetLastError returns ERROR_INVALID_THREAD_ID if idThread is not a valid thread identifier, or if the thread specified by idThread does not have a message queue.
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  10. #10
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Points : 1 051
    Points
    1 051
    Par défaut
    ouep je vais essayer voir ce que ça dit.

    Je me disais aussi que l'event pouvais aussi très bien être remplacé par un booléen volatile dans ce cas.

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Et faire une boucle d'attente active/semi-active? Beurk!
    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.

  12. #12
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Points : 1 051
    Points
    1 051
    Par défaut
    En fait je l'ai lu ici et je me disais que ça permettait de ne pas avoir à se soucier ensuite de la libération du handle de l'event.
    http://msdn.microsoft.com/en-us/library/12a04hfd.aspx

    Mais effectivement, après test, Sleep( 0 ) est très consommateur du processeur. Donc pas top.

    Je n'ai pas cherché encore mais Sleep(0) est sencé rendre la main aux autres threads si besoin c'est ça ? Celà inclut-il les threads des autres process ?

    Voila un deuxième exemple en C# qui me parait suspect aussi, avec la boucle sur isalive http://msdn.microsoft.com/en-us/libr...y4(VS.80).aspx

  13. #13
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    27
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 27
    Points : 33
    Points
    33
    Par défaut
    Citation Envoyé par NiamorH Voir le message
    Avec ce code, jusqu'à NBMESSAGES = 6000 tou va bien, mais au dessus les messages se perdent.

    Bon j'aurais surement rarement l'occasion d'en envoyer autant comme ça dans une appli de toute manière...

    ]

    Pour avoir fait des essais, je ne pense pas que 6000 soit une limite, c'est juste que vous envoyer plus de messges que le thread n'as le temps d'en traiter et donc à un moment on arrive à saturation, ce qui ne devrait jamais arriver dans une application réelle.

    Il suffit de rajouter un sleep dans le thread envoyant les messages pour s'en rendre compte.

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

Discussions similaires

  1. sur activation qui apparait trop tot à l'ouverture
    Par petitours dans le forum IHM
    Réponses: 4
    Dernier message: 23/03/2008, 15h27
  2. Eclipse trop lent après le ant!
    Par filot dans le forum Eclipse Java
    Réponses: 1
    Dernier message: 31/08/2007, 08h21
  3. Page rechargée trop tot
    Par leyee dans le forum ASP.NET
    Réponses: 3
    Dernier message: 21/06/2007, 13h03
  4. [Dev-Pascal] Mon programme se ferme trop vite après la dernière instruction
    Par am002r dans le forum Autres IDE
    Réponses: 4
    Dernier message: 08/05/2007, 10h25
  5. [Java3D] Collison : Trop tot
    Par akito dans le forum 3D
    Réponses: 4
    Dernier message: 11/04/2007, 14h35

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