Boucle infinie sous XP Pro FR, mais pas sous les autres OS

Boucle infinie sous XP Pro FR, mais pas sous les autres OS - C++ - Programmation

Marsh Posté le 13-07-2004 à 11:00:10    

Bonjour, une fois de plus j'ai un problème avec la programme que je développe:
 
Un des modules de ce programme permet d'acquérir des données à partir du port série, il fonctionne parfaitement sous les PCs équipés de Windows 98/Me, et aussi sous un PC équipe de XP Pro multilingue. En revanche, sur un PC équipé de XP Pro FR j'avais un plantage (boucle infinie) en sortie de ce module à chaque fois, plantage qui dispairaissait si on utilisait le mode de compatibilité Win2000. Depuis peu le PC sous XP Pro multilingue a été passé à XP Pro FR, et il me fait le même problème que l'autre...
 
J'ai trouvé la cause de la boucle infinie, mais pas la raison...

Code :
  1. // ARRET DES THREADS
  2. SetEvent(stop_thread2);
  3. thread2->SetThreadPriority(THREAD_PRIORITY_ABOVE_NORMAL);
  4. ResumeThread(thread2->m_hThread);
  5. Sleep(0);
  6. WaitForSingleObject(thread2->m_hThread,INFINITE);
  7. // AfxMessageBox("Thread 2 finie" );
  8. CloseHandle(stop_thread2);
  9. SetEvent(stop_thread1);
  10. thread1->SetThreadPriority(THREAD_PRIORITY_ABOVE_NORMAL);
  11. ResumeThread(thread1->m_hThread);
  12. Sleep(0);
  13. WaitForSingleObject(thread1->m_hThread,INFINITE); //C'est cette ligne de code qui déclenche une boucle infinie sur les pc équipés de Win XP Pro FR SP1
  14. // AfxMessageBox("Thread 1 finie" );
  15. CloseHandle(stop_thread1);
  16. // LIBERATION DE LA MEMOIRE
  17. if(releves_force!=NULL)
  18.  free(releves_force);
  19. if(releves_deplacement!=NULL)
  20.  free(releves_deplacement);


 
Le thread 2 gère l'affichage des courbes à l'écran et s'arrête parfaitement, le thread 1 gère les communications avec le port série, voilà son code:

Code :
  1. DWORD WINAPI Thread1(LPVOID pParam)
  2. {
  3. /**************************************************************/
  4. CAcquisition *classe;
  5. classe=(CAcquisition *)pParam;
  6. HWND hwnd=classe->GetSafeHwnd();
  7. /**************************************************************/
  8. char commande[7];
  9. DWORD dwCommModemStatus,octets_lus,octets_envoyes;
  10. int decompte;
  11. BOOL defaut;
  12. char buffer[16];  //[16] pour permettre plus de souplesse vis à vis des futures acquisitions avec plus de valeurs
  13. strcpy(commande,"$01R1" );
  14. commande[5]=0x0D;  //'\n'
  15. commande[6]=0x00;  //Fin de string
  16. classe->defaut_capteur_deplacement=FALSE;
  17. classe->defaut_capteur_force=FALSE;
  18. SetCommMask(classe->hPort,EV_RXCHAR);
  19. while((WaitForSingleObject(classe->stop_thread1,0)!=WAIT_OBJECT_0)&&
  20.   (classe->hPort!=INVALID_HANDLE_VALUE))
  21. {
  22.  // communication avec le capteur de déplacement
  23.  commande[2]='1';  //$01R1
  24.  WriteFile(classe->hPort,commande,6,&octets_envoyes,&classe->overlapped);
  25.  WaitForSingleObject(classe->overlapped.hEvent,INFINITE);
  26.  // réception de la réponse (XX.XXmm)
  27.  // test si défaut capteur
  28.  decompte=0;
  29.  defaut=FALSE;
  30.  while((!defaut)&&(decompte<4))
  31.  {
  32.   Sleep(25); // 100ms de time-out
  33.   WaitCommEvent(classe->hPort,&dwCommModemStatus,&classe->overlapped);
  34.   if(dwCommModemStatus&EV_RXCHAR)
  35.    defaut=TRUE;
  36.   decompte++;
  37.  }
  38.  // attente réception complète des données (8 octets en tout, 0x0D compris)
  39.  if(dwCommModemStatus&EV_RXCHAR)
  40.  {
  41.   ReadFile(classe->hPort,buffer,8,&octets_lus,&classe->overlapped);
  42.   buffer[7]=0;
  43.   classe->position_capteur_deplacement=classe->chaine_double(buffer);
  44.   classe->defaut_capteur_deplacement=FALSE;
  45.  }
  46.  else
  47.  {
  48.   // impossible de lire le capteur
  49.   // vider les buffers
  50.   PurgeComm(classe->hPort,PURGE_TXCLEAR);
  51.   PurgeComm(classe->hPort,PURGE_RXCLEAR);
  52.   PurgeComm(classe->hPort,PURGE_TXABORT);
  53.   PurgeComm(classe->hPort,PURGE_RXABORT);
  54.   SetCommMask(classe->hPort,EV_RXCHAR);
  55.   // signaler l'erreur à l'écran
  56.   classe->defaut_capteur_deplacement=TRUE;
  57.  }
  58.  // communication avec le capteur de force
  59.  commande[2]='2';  //$02R1
  60.  WriteFile(classe->hPort,commande,6,&octets_envoyes,&classe->overlapped);
  61.  WaitForSingleObject(&classe->overlapped,INFINITE);
  62.  // réception de la réponse (XX.XXkN)
  63.  // test si défaut capteur
  64.  decompte=0;
  65.  defaut=FALSE;
  66.  while((!defaut)&&(decompte<4)) //100ms de time-out
  67.  {
  68.   Sleep(25);
  69.   WaitCommEvent(classe->hPort,&dwCommModemStatus,&classe->overlapped);
  70.   if(dwCommModemStatus&EV_RXCHAR)
  71.    defaut=TRUE;
  72.   decompte++;
  73.  }
  74.  // attente réception complète des données (8 octets en tout, 0x0D compris)
  75.  if(dwCommModemStatus&EV_RXCHAR)
  76.  {
  77.   ReadFile(classe->hPort,buffer,8,&octets_lus,&classe->overlapped);
  78.   buffer[7]=0;
  79.   classe->position_capteur_force=classe->chaine_double(buffer);
  80.   classe->defaut_capteur_force=FALSE;
  81.  }
  82.  else
  83.  {
  84.   // impossible de lire le capteur
  85.   // vider les buffers
  86.   PurgeComm(classe->hPort,PURGE_TXCLEAR);
  87.   PurgeComm(classe->hPort,PURGE_RXCLEAR);
  88.   PurgeComm(classe->hPort,PURGE_TXABORT);
  89.   PurgeComm(classe->hPort,PURGE_RXABORT);
  90.   SetCommMask(classe->hPort,EV_RXCHAR);
  91.   // signaler l'erreur à l'écran
  92.   classe->defaut_capteur_force=TRUE;
  93.  }
  94.  // boucle
  95.  SetCommMask(classe->hPort,EV_RXCHAR);
  96. };
  97. /**************************************************************/
  98. AfxEndThread(0,TRUE);
  99. return 0;
  100. /**************************************************************/
  101. }


 
Donc, voyez vous pourquoi mon programme tourne parfaitement sous 98/Me/2000/XP Pro Multilingue, et plante sous XP Pro FR?


Message édité par Alkor2001 le 13-07-2004 à 11:01:10

---------------
J'aime pas Apple...
Reply

Marsh Posté le 13-07-2004 à 11:00:10   

Reply

Marsh Posté le 13-07-2004 à 15:55:30    

:bounce:


---------------
J'aime pas Apple...
Reply

Marsh Posté le 13-07-2004 à 16:07:17    

Citation :

Sleep(0);  
   WaitForSingleObject(thread1->m_hThread,INFINITE); //C'est cette ligne de code qui déclenche une boucle infinie sur les pc équipés de Win XP Pro FR SP1


La raison est simple : ton thread 1 ne se termine pas.
Au passage, ton Sleep(0) ne sert à rien (WaitForXXX met ton programme en attente)
Donc le bug est dans thread 1. Donc faut que tu traces l'exécution de ton thread 1 jusqu'à trouver là ou ça va pas.
L'histoire de la langue c'est bizarre, c'est pas une histoire de mises à jour et de service pack plutôt ?


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 13-07-2004 à 16:12:50    

HelloWorld a écrit :

Citation :

Sleep(0);  
   WaitForSingleObject(thread1->m_hThread,INFINITE); //C'est cette ligne de code qui déclenche une boucle infinie sur les pc équipés de Win XP Pro FR SP1


La raison est simple : ton thread 1 ne se termine pas.
Au passage, ton Sleep(0) ne sert à rien (WaitForXXX met ton programme en attente)
Donc le bug est dans thread 1. Donc faut que tu traces l'exécution de ton thread 1 jusqu'à trouver là ou ça va pas.
L'histoire de la langue c'est bizarre, c'est pas une histoire de mises à jour et de service pack plutôt ?


 
Merci, en fait je me suis mal exprimé, je me doute bien que le problème vient du thread 1 qui ne se termine pas (d'où la boucle infinie à cause de mon argument INFINITE), mais dans ce thread je n'arrive pas à trouver l'erreur, surtout que ça n'arrive QUE sur les pc sous XP Pro FR (et que bien entendu je code sous 98, et je n'ai pas de PC XP facilement accessible  :sweat:  pour tester)
 
Sinon, oui je suppose qu'il s'agit d'un problème de mises à jour, mais j'ai fait tout ce que je pouvais avec les Windows Update, et ça n'a rien arrangé...
 
PS: Merci pour le sleep(0), tu as tout à fait raison...  :jap:


Message édité par Alkor2001 le 13-07-2004 à 16:13:42

---------------
J'aime pas Apple...
Reply

Marsh Posté le 13-07-2004 à 16:27:59    

Ben affiche des messages pour voir où il bloque...


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 19-07-2004 à 11:27:52    

Bon, dans mon thread c'est cette ligne là qui pose problème:

Code :
  1. WaitForSingleObject(classe->overlapped.hEvent,INFINITE);


 
Alors je veux bien virer le INFINITE, mettre en place un time-out et une gestion des erreurs, mais j'aimerais d'abord comprendre pourquoi cette ligne ne déclenche une boucle infinie QUE sous Xp Pro FR?  :??:


---------------
J'aime pas Apple...
Reply

Marsh Posté le 19-07-2004 à 12:22:47    

Je sais pas, mais en tous cas elle sert à rien :
- Tu demande à faire une écriture asynchrone juste avant avec WriteFile
- tu fais une attente synchrone juste après...
Fais un WriteFile normal sans utiliser l'overlapp et vire tes WaitForSingleObject après tes Read/WriteFile.
hum...

Code :
  1. ReadFile(classe->hPort,buffer,8,&octets_lus,&classe->overlapped);
  2.            buffer[7]=0;


Ca doit pas faire quelque chose de bien ça. Lecture asynchrone -> ReadFile rend la main sans que la lecture ait été faite. Rajoute un WaitForSingleObject après le ReadFile pour voir...
Et tes Sleep(25); avant tes fonctions d'attente ils servent à rien, voire ils pénalisent.
Tu comprends ce que tu écris ?


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 19-07-2004 à 14:23:17    

Ce n'est pas moi qui ai écrit cette partie du programme, mais le précédent stagiaire. J'avoue que je n'ai pas bien compris la façon dont il avait mis en place ses threads de communication avec le port série, mais vu que tout fonctionnait parfaitement jusqu'à maintenant, je ne voulais pas y toucher et risquer de créer des problèmes...
 
Enfin merci pour tes indications, je vais aller faire un tour sur la msdn pour éclaircir un peu tout ça!  :hello:


Message édité par Alkor2001 le 19-07-2004 à 14:23:57

---------------
J'aime pas Apple...
Reply

Marsh Posté le 20-07-2004 à 10:15:10    

Oui, ça sent le code pompé sur internet :)
En gros en utilisant les overlapped io, les lectures/écritures sont asynchrones => WriteFile/ReadFile rendent la main sans avoir fait leur boulot. Celui-ci est mis dans une file d'attente et dès qu'il est fait l'évènement associé dans la struct overlapped est déclanché, d'ou le WaitForSingleObject afin de se synchroniser. Il l'a mis pour WriteFile, mais pas pour ReadFile, et c'est une erreur. Ca doit marcher parce que le temps que le programme se termine la lecture est faite. Par contre je sais pas trop dans quel etat est l'évènement.
Le plus simple, c'est de faire simple !
Pas d'io asynchrone, mais du bon vieu synchrone, ReadFile/WriteFile avec NULL pour la struct overlapped, et alors ils sont bloquants, et alors plus besoin de Sleep ou WaitForSingleObject.
Ca pourrait être justifié sur ReadFile pour gérer un timeout, mais c'est même pas le cas (INFINITE).


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 14-03-2005 à 15:36:06    

Bonjour !
 
je programme en c, pas en c++, mais le sujet etant la comm serie avec win32, je me suis dit que ma question serait aussi bien ici.
 
En fait, je dois faire un programme qui lit un fichier ligne par ligne et envoie chaque ligne par lien serie a un microcontrolleur.
 
Suivant tes conseils, je fais de la comm synchrone (pas overlap). J'ai ajoute des time out, pour pas rester infiniement en attente.  
Si la lecture de l'aquitement ne se fait pas (apres time out) je reecrit la ligne (jusqu'a 10 ecritures, apres, error, mais ca on s'en fout).  
 
Lorsque le time out est assez grand pour ne pas avoir a reecrire la ligne, mon prog marche.  
 
        tTimeout.ReadTotalTimeoutMultiplier = 5;  
        tTimeout.ReadTotalTimeoutConstant = 30;
 
Par contre, pour des valeurs faibles, necessitant la reexpedition de la ligne, ca ne marche plus
 
        tTimeout.ReadTotalTimeoutMultiplier = 1;  
        tTimeout.ReadTotalTimeoutConstant = 1;
 
alors que le logiciel qui lit les communications sur le lien serie m'indique que c'est bien la meme ligne qui est transmise de nouveau
 
IRP_MJ_WRITE S315FC1015C000000DC400000DC800000DCC00000DD0AD  
IRP_MJ_READ Serial0 TIMEOUT Length 0:  
IRP_MJ_WRITE S315FC1015C000000DC400000DC800000DCC00000DD0AD  
IRP_MJ_READ Serial0 SUCCESS Length 8: R10200FD  
 
   Si tu (ou quelqu'un d'autre) a des explication...
   Peut etre que ces valeurs de time out sont trop faibles et que windows ne les prend pas en compte (pourtant le programme se comporte bien...).  
   Peut etre que je ne devrait pas renvoyer de nouveau la meme ligne, juste attendre, sinon, la nouvelle ligne s'ajoute a une ligne a moitie lue, cote microcontrolleur ???
   Peut etre que ...
 
Merci beaucoup !
 
Olivier

Reply

Marsh Posté le 14-03-2005 à 15:36:06   

Reply

Marsh Posté le 14-03-2005 à 16:19:05    

Je pige pas bien, à commencer pourquoi tu n'as pas créé un nouveau topic.
Comment tu détectes le timeout ?


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 14-03-2005 à 16:28:26    

aie, aie, aie !
 
   c'est quoi un topic ? (je suis pas un pro !)
 
   Cela dit, j ai l'impression que le fait de parametrer le time out (et de faire 'SetCommTimeouts') le rend directement efficace. Si je change les valeurs, (si je met quelques secondes, par exemple), j'observe ces changements, grace au logiciel qui chope les communication sur port serie (il y a bien plusieurs secondes avant la re emission de la trame).
 
C'est peut etre pas encore tres clair...

Reply

Marsh Posté le 14-03-2005 à 16:52:14    

pour le topic, g compris (ben quoi, je croyais que c t 1 truc en langage c, et pis alors ?...) !!!
 
je ne vois pas ce que tu entends par 'detecter le time out'

Reply

Marsh Posté le 14-03-2005 à 17:04:55    

Citation :

IRP_MJ_READ Serial0 TIMEOUT Length 0:


Comment tu tests si y'a timeout ?
je pige pas ta remarque aussi:

Citation :

Cela dit, j ai l'impression que le fait de parametrer le time out (et de faire 'SetCommTimeouts') le rend directement efficace.


c'est quoi "efficace" ?


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 14-03-2005 à 17:13:58    

IRP_MJ_READ Serial0 TIMEOUT Length 0:
 
je fais ca :
 
//initialisation de tous les parametres du time out
SetCommTimeouts()
 
...
 
WriteFile()
ReadFile()
 
et j'ai l'impression qu'effectivement, en faisant ca, a chq appel de WriteFile() et ReadFile(), il y a un time out de lance... Ca ne te semble pas normal ? c pas comme ca que ca marche ?
 
 
Pour ce qui est de cette ligne :
 
IRP_MJ_READ Serial0 TIMEOUT Length 0:
 
c est ce que j'observe comme communication sur port serie. Si je met un time out de plusieurs secondes et que j'eteind le microcontroleur, je vois ca :
 
IRP_MJ_READ
 
puis, qq secondes plus tard, ca a la place :
 
IRP_MJ_READ Serial0 TIMEOUT Length 0:
 
 
...

Reply

Marsh Posté le 14-03-2005 à 17:42:32    

je file !
 
 
merci pour tes reponses.. tu seras peut etre encore la demain ?!
 
++

Reply

Marsh Posté le 14-03-2005 à 23:50:37    

Bon je vais aller au bout de ma pensée : pour détecter le timeout il faut tester le nombre d'octets lus / écris. S'il vaut 0 ou n'est pas celui attendu c'est que y'a timeout.
Apparement c'est pas toi qui écrit ce que tu as donné en citation (IRP_MJ_READ Serial0 TIMEOUT Length 0: ).


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 15-03-2005 à 09:28:18    

Oui, pardon, ca je le fais ! Ca donne qqch comme ca :
 
read_byte(au8FrameR, u8LenR, &dwNbRead);
     if (dwNbRead == u8LenR)
          if (checkResult (au8FrameR, au8FrameE, u8LenR))
               return OK;
 
Je repose ma question mieux :
 
j'ecris une trame sans pb.
 
Le microcontrolleur est cense repondre a cette trame dans un delai court.
 
Si il ne repond pas avant la fin du time out (en clair, si a la sortie du read, il n'y a pas autant de caracteres lus que prevu), est ce que tu crois que je dois :
 - reecrire ma trame et refaire une lecture de la reponse (on recommence tout, quoi)
 - relancer une lecture sans rien reecrire avant  (la reponse lue sera-t-elle une concatenation des deux petits bouts de reponse ?)
 - faire en sorte que dans un fonctionnement normal, ce cas ne se produise pas, donc simplement alonger le time out (de maniere a ce que le micro est le temps de repondre si tout va bien) dans ce cas, le time out declencherai une sortie du programme, et une indication d'erreur
 
 
Pour l'instant, j'opte pour la premiere solution.
 
Les communications que j'observe sur le lien serie sont celle-ci (effectivement, il ne s'agit pas de mon code, mais bien de ce qui s'affiche sur le terminal d'un logiciel qui scrute le lien serie) :
 
 
emission de la trame :
IRP_MJ_WRITE Serial0 SUCCESS Length 46: S315FC10157000000D7400000D7800000D7C00000D803D  
 
lecture de la reponse, mais time out trop court => pas de reponse (le logiciel detecte les time outs)
IRP_MJ_READ Serial0 TIMEOUT Length 0:  
 
re emissiom
IRP_MJ_WRITE Serial0 SUCCESS Length 46: S315FC10157000000D7400000D7800000D7C00000D803D  
 
lecture de l'aquittement :
IRP_MJ_READ Serial0 SUCCESS Length 8: R10200FD  
 
 
La trame emise et celle reemise sont bien les memes. L'aquitement recu est correct. Pourtant, lorsqu'il y a comme cela besoin de reemettre, le programme ne fonctionne pas, au final, sur le micro. Si tu as des idees
...
 
Merci !!!  

Reply

Marsh Posté le 15-03-2005 à 15:29:10    

Je comprends pas ce qui marche pas. Tu dis que tout va bien, mais que ça marche pas.


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 16-03-2005 à 09:19:39    

exact !
 
En fait, une fois le programme charge et execute, le microcontroleur doit faire clignoter des diodes.  
 
Qd y a pas de time out detectes, les diodes se mettent a clignoter.  
Qd il y en a, elles ne clignotent pas.  
 
Dans ce cas, le programme a donc ete incorrectement recu, alors que les trames ont l'air bonne, d'ou mon incomprehension.
 
Penses tu que c'est une erreur de reexpedier la trame apres le time out ? (car il y a deja une trame a moitie lue qq part et que ca cree des conflits)
 
En gros, ca marche en mettant des times out longs , mais je ne comprend pas que ca marche pas avec la reexpedition dans le cas de time out courts.
 
Merci
 
Olivier

Reply

Marsh Posté le 16-03-2005 à 09:43:23    

A priori si y'a timeout d'ecriture le contenu ecrit est perdu. Mais peut etre que le microcontrolleur en lit une partie et fait timeout au milieu.
Ce qui est sûr c'est que c'est pas une bonne idee d'avoir des timeout très petits (<10 ms), Windows n'est pas temps réel.


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 16-03-2005 à 10:02:50    

dac !  
 
ca reste un peu bizarre, mais ca me plait, comme reponse : mes times outs etaient effectivement inferieurs a 10 ms !
 
merci

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed