Sémaphore Posix anonyme - comportement inexpliqué

Sémaphore Posix anonyme - comportement inexpliqué - C++ - Programmation

Marsh Posté le 28-12-2008 à 01:57:07    

Bonjour,
J'ai un souci avec les sémaphore Posix anonyme utilisés dans la synchronisation de threads. Je tiens d'abords à poser le contexte.. attention, accrochez-vous!
 
Mes threads permettent d'activer certaines sous-routines qui sont chacune liées à un flag. Ceux-ci sont testés dans une boucle infinie exécutée dans le thread qui est bloqué à chaque boucle par un sémaphore (sem_wait()). Avec le code, ce sera peut-être plus clair :
 

Code :
  1. //fonction exécutée dans un thread détaché du fil d'exécution principal du programme
  2. void maFonctionThreadee()
  3. {
  4.   while(true)
  5.   {
  6.     if(maSousRoutine1_activee)
  7.     {
  8.       maSousRoutine1_activee = false;
  9.       maSousRoutine1_Privee();
  10.     }
  11.     else if(maSousRoutine2_activee)
  12.     {
  13.       maSousRoutine2_activee = false;
  14.       maSousRoutine2_Privee();
  15.     }
  16.     //...
  17.    
  18.     //arrête le thread jusqu'à la prochaine activation
  19.     sem_wait(&monSemaphore);
  20.   }
  21. }
  22. //fonction public appelée depuis le fil d'exécution principal du programme
  23. void MaSousRoutine1_Public()
  24. {
  25.   maSousRoutine1_activee = true;
  26.   //activation de la boucle dans la fonction "threadée"
  27.   sem_post(&monSemaphore);
  28. }
  29. //fonction privée, appelée depuis la boucle de la fonction "threadée"
  30. void maSousRoutine1_Privee()
  31. {
  32.   //code traitement
  33. }


 
Je dois interrompre ce thread de manière asynchrone.  
 
J'arrive à le faire car lors de l'initialisation du thread, je paramètre l'activation des interruptions avec :

Code :
  1. pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
  2. pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);


Et je l'interromps avec l'appel à la fonction :

Code :
  1. pthread_cancel(referenceAuThread);


 
Le thread s'interrompt bien.
Lorsque je réinitialise le thread, je réinitialise en premier les flags d'activation relatifs aux sous-routines, ainsi que le sémaphore utilisé pour bloquer/activer la boucle de la manière suivante :

Code :
  1. //destruction de l'ancien sémaphore
  2. sem_destroy (&monSemaphore);
  3. //initialisation du nouveau sémaphore
  4. //(initialiser à 0, ainsi au premier sem_wait, il attendra jusqu'à qu'on active
  5. //une des sous-routine et qu'un sem_post soit effectué).
  6. sem_init(&monSemaphore, 0, 0);


Ensuite, l'initialisation du thread :

Code :
  1. // le thread est detaché
  2. pthread_attr_setdetachstate(&pthread_attr_t,PTHREAD_CREATE_DETACHED);
  3. //initialise le thread et le lance dans la méthode maFonctionThreadee
  4. pthread_create(&referenceAuThread, &pthread_attr_t, maFonctionThreadee)


 
 
Voilà, donc pour en arriver au fait.. J'arrive à interrompre mes threads, à les réinitialiser et à les relancer. Cependant, parfois de manière inattendue, après avoir relancer mes threads, lorsque j'effectue un sem_post sur le sémaphore monSemaphore pour activer la boucle, celui-ci s'incrémente bien (j'ai vérifié avec la fonction sem_getvalue()), mais le thread en attente sur le sem_wait dans la boucle infinie ne se débloque pas...
 
J'ai lu dans la doc MAN, que de faire un sem_destroy(&monSemaphore) alors que ce sémaphore a des threads en attente, peut amener un comportement indéfini :

Citation :

“Destroying a semaphore that other processes or threads are currently blocked on (in sem_wait(3)) produces undefined behaviour.”

Linux MAN page  
 
8O
 
Est-ce que cela pourrait-il être la cause de mon problème? Pourtant, j'ai l'impression de tout réinitialiser proprement et deux fois sur trois, cela fonctionne très bien.. Vive les bugs de concurrence!
 
Merci d'avance pour votre aide, j'en ai un grand besoin! :?
Alex

Reply

Marsh Posté le 28-12-2008 à 01:57:07   

Reply

Marsh Posté le 28-12-2008 à 09:19:37    

Code :
  1. void maFonctionThreadee()
  2. {
  3.   while(!maConditionDArretDuThread)
  4.   {
  5. //......
  6. void MaSousRoutineDArret_Public()
  7. {
  8.   maConditionDArretDuThread = true ;
  9.   sem_post(&monSemaphore);
  10. }


 
 :??:  
 
Comme ca t'as pas à détruire/recontruire ton objet de synchro, le thread se sort proprement, toussa ? (c'est à la louche, je connais pas les API utilisées ici...)

Reply

Marsh Posté le 28-12-2008 à 12:16:43    

Oui, mais j'ai des sous-routines qui prennent du temps à s'exécuter. Je dois pouvoir interrompre ces traitements instantanément.

Reply

Marsh Posté le 28-12-2008 à 12:54:24    

Tuer des threads, c'est comme tuer des chatons, cay mal :o
 
Si ton traitement dure longtemps, bah tu peux essayer de te débrouiller pour que le dit traitement teste de temps en temps la condition maConditionDArretDuThread. Si ce n'est pas possible, bah c'est dommage (mais dans ce cas, tu peux tuer le thread sans qu'il ne soit en train d'attendre dans son sem_wait(), et donc t'as pas le problème de comportement indéfini précisé dans la doc... - fais quand même gaffe aux ressources utilisées par ton traitement dans le thread et qu'il ne pourrait libérer en cas d'arrêt de brutasse...)

Reply

Marsh Posté le 28-12-2008 à 14:01:27    

J'ai obtenu l'explication de ce comportement indéfini sur un autre forum en anglais :
http://www.linuxforums.org/forum/l [...] post654519
 
Une manière plus propre que d'utiliser un booléen est l'utilisation d'interruption différée avec l'utilisation de point d'interruption "Cancellation points".
 
Merci quand même pour votre aide,
Alexandre

Reply

Marsh Posté le 28-12-2008 à 18:36:23    

Ouaip enfin ca revient au même, ils disent juste que tuer des threads, c'est mal, et te disent de mettre ce qu'il faut dans le code de ton thread pour qu'il soit capable de se fermer proprement tout seul si besoin.

Reply

Marsh Posté le 28-12-2008 à 18:41:59    

Mackila a écrit :

Ouaip enfin ca revient au même...


Il y a une différence entre tester un booléen homemade et utilisé des fonctionnalités POSIX prévus pour faire cela proprement comme tu dis..

Reply

Sujets relatifs:

Leave a Replay

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